条件式でビット演算子を使用するのが適切な場合


15

まず、いくつかのバックグラウンド:私はトレーニング中のIT教師であり、10年生のクラスにjavaのブール演算子を導入しようとしています。教師と指導者は、準備したワークシートを確認し、単一の&または|を使用できるとコメントしました。「同じことをする」ため、演算子を示します。

&と&&の違いを認識しています。
&は、整数間の使用を目的としたビット単位の演算子で、「ビットトゥイドリング」を実行します。
&&は、ブール値間で使用するための条件演算子です。

これらの演算子が常に「同じことをする」わけではないという点を証明するために、ブール値間でビット単位を使用するとエラーが発生する例を見つけました。この例を見つけました

boolean bitwise;
boolean conditional;
int i=10, j=12;
bitwise = (i<j) | ((i=3) > 5); // value of i after oper: 3
System.out.println(bitwise+ " "+ i);
i=10; 
conditional = (i<j) || (i=3) > 5 ;  // value of i after oper: 10
System.out.println(conditional+ " "+ i);
i=10; 
bitwise = (i>j) & (i=3) > 5;   // value of i after oper: 3
System.out.println(bitwise+ " "+ i);
i=10; 
conditional = (i>j) && (i=3) > 5;  // value of i after oper: 10
System.out.println(conditional+ " "+ i);

この例は、式の後半で値を変更する必要がある場合、ビットワイズは熱心な演算子であり、条件は短絡回路として動作するため、結果の違いにつながることを示しています(2番目を評価しません前半が&&の場合にfalse、||の場合にtrueの場合、半分。

この例には問題があります。比較するのと同時に値を変更したいのはなぜですか?堅牢なコーディング方法とは思えません。私は常に、本番コードで1行で複数の操作を行うことを嫌っていました。彼のコードの保守性に関して良心のない「コーディングカウボーイ」がするように思えます。一部のドメインでは、コードをできるだけコンパクトにする必要があることを知っていますが、これは一般的に悪いプラクティスですか?

&&および||の使用を奨励する私の選択を説明できます。以上&| これはソフトウェアエンジニアリングで受け入れられているコーディング規則であるからです

しかし、誰かが条件式でビットごとの演算子を使用するより良い、実際の世界の例を教えてもらえますか?

回答:


16

マスキング操作を実行するときに適切です

if((a&b)> 0){...}

ここで、aとbは整数です

|| と| and &&および&は交換できません

| そして&が条件式に単独で現れることはほとんどありません(あなたが含めたリンクのポイントは、そのようなものはほとんどの場合エラーであるということです)

編集:あなたのメンターと議論しないでください。たとえあなたが勝ったとしても、あなたは負けます。代わりに、同じレッスンで論理演算子とビット演算子を組み合わせて、生徒を混乱させたくないことを説明します。i = 3およびj = 2の場合、i&j = 2であり、i && jはエラーであると説明できます。ただし、より単純な説明は、ブール(論理)演算子を教えているということです。そのため、特殊な場合のビット単位の同等物をスローすることは、レッスンの要点からの注意散漫です。メンターを「間違った」ものにする必要はなく、反例を作成する必要もありません。レッスンの焦点は、ビット演算子ではなくブール演算子にあります。

当然のことながら、ビット単位の演算子を教え始めるとき、+と-が&と|と同じ結果を生成する特別なケースを示す必要はありません。


上記のコードは間違っていませんが、紛らわしいかもしれませんが、コードにエラーが含まれていないので、それはそうですか?このようにビット単位の演算子を使用することはあまり読みやすくないことに同意します。コードレビューで見た場合は気に入らないでしょうが、正当なJava(およびC#もSystem.out.printlnを無視する)です。
スティーブ

@Steven A. Loweにお答えいただきありがとうございます。「||と|および&&と&は互換性がない」と言いましたがbitwise = !(true & true == false);condition = !(true && true == false);両方ともtrueと評価されるので、この場合、それらは互換性がありますか?コードはまだコンパイルされているので、おそらく構文的に。段落2で述べたように、それらが意味的に異なるものに使用されることに同意します。および&「条件自体にほとんど決して現れない」。これらの「ほとんどない」ケースを探しており、それらが合法的に存在するかどうか疑問に思っています。
ディアシャ

@Deerasha:|| および&& はブール値に対してのみ動作します。&および| 整数ブール値を操作する-ブール値を操作するためにビット演算子(複数のビットを操作することを意図している)を使用することはほとんど意味がありません。ブール値、ビット演算子は文句を言わない)
スティーブンA.ロウ

はい、@ Steve Haigh、コンパイラはそれを拒否しませんが、私がリンクしている公開されたコーディング標準から判断すると、それらを使用する正しい方法ではありません。コーディング標準に準拠していないため、それを却下することに安心できますか、またはjavaがこれが不適切な使用であることを示す必要がありますか?
ディアシャ

2
@Steven A. Lowe:i = 3およびj = 2の場合、i&j = 2ですが、i && jはエラーですが、これは素晴らしいです!それは簡単であり、ポイントを作ります。10年生レベルでは、これは間違いを犯す可能性が高いため、まだブール型と演算子の適用対象に慣れているためです。どうもありがとうございます!私の指導者とも議論しないことに関する素晴らしいアドバイス。
ディアシャ

12

ビット単位ではない演算子&&||は、短絡演算子です。つまり、で&&、LHSがfalseの場合、RHSは評価されません。||LHSが真であれば、その後、RHSが評価されることはありません。一方、ビット単位演算子&|は非短絡であり、常にLHSとRHSの両方を評価します。それ以外の場合、それらはifステートメントで同等です。

非短絡演算子を使用して価値を確認できるのは、RHSにあらゆる場合に発生させたい望ましい副作用がある場合だけです。あなたがこれを望む特定の例を考えることはできませんし、それが良い習慣だとは思いませんが、それは違いです。


1
+1。正確に言えば、ビット単位の論理演算子と論理演算子を比較すると、常に同じ結果が返されますが、(少なくともJavaとC#では)論理演算子のみが短絡します。
スティーブ

答えてくれてありがとう。段落1は、段落4で取得しようとしていたもので、ビット単位は熱心な演算子であり、条件は短絡として動作するということです。あなたのパラグラフ2は、私のパラグラフ5で説明した懸念です。そのため、違いは承知していますが、あなたも私も考えられない特定の例を探しています。
ディアシャ

7

一般的な哲学的答えは、ブール演算子にビット演算子を使用することは非定型であり、コードを読みにくくすることです。実際には(運用中のコードの場合)、読みやすいコードの方が保守が容易であるため、望ましいコードです。

短絡演算子の必要性を実際に使用するには、次のようなケースを参照してください。

if (args.length > 0 && args[0] == 'test') ....

if (b != NULL && b.some_function()) ...

if (b == NULL || b.some_function()) ...

これらのタイプの操作は、実際のコードに頻繁に現れます。


Tfa。15歳の子供に、1 &は2より「読みにくい」と説明するにはどうすればよいですか。2つの演算子がブールオペランドに対して同じように機能しない例はありません。コードを読みやすく、保守しやすいという点に同意します。私は彼らに美しいコードを書くことを奨励したい。しかし、ツールのバッグに何らかの証拠があると、「そう言ったから」よりも説得力があります。私はそれをそのリンクの標準として述べており、探している例が得られない場合はそれだけに頼らなければならないかもしれません。私が@Steve Haighに尋ねたように:javaはこれを不適切な使用として示しているべきですか?
ディアシャ

@Deerashaあなたのメンターとの議論をもっと考えていました。クラスの場合、論理条件にビット演算子を使用できることを伝えようとしないでください。
キャシーヴァンストーン

4

ビットマスク列挙を比較する場合は、ビットごとの演算子を使用します。たとえば、状態の列挙と、それらの状態の複数になることができるオブジェクトがあります。この場合、ビット単位で行うか、オブジェクトに複数の状態を割り当てます。

例えばstate = CONNECTED | IN_PROGRESSどこCONNECTED could be 0x00000001IN_PROGRESS 0x00000010

詳細については、フラグ列挙ドキュメントを参照してください。


おかげさまで、これまで知らなかったビット演算子のアプリケーションを学びました!ただし、この例で、ビット演算子のみが適用されます。条件付きではなくビット単位を使用するとコンパイルにつながるが、出力が正しくない、よく書かれたコードを探しています。つまり、そのようなコードスニペットが存在する場合です。
ディアシャ

これをJavaで呼び出すことはできないと思います。ビット単位のand'd or or'dにできない値のor演算子は、論理的な|を実行するだけです。または&。これがJavaの場合かどうかは思い出せませんが、C#MSDNにあることは確かです。 boolオペランド、|オペランドの論理ORを計算」
-pwny

さらに調査を重ねた結果、|の唯一の違いがわかりましたおよび|| Javaのブールオペランドの&および&&は短絡動作であるため、説明しているシナリオは実際には不可能です。
-pwny

0

単純な誤りの例:

int condA=1, condB=2;

if (condA!=0 && condB!=0) {
    // correct!
}
if ((condA & condB)!=0) {
    // never executed
}

ここには2つの条件がありますが、どちらもゼロではありません。しかし、ビット単位の&結果はゼロになります。


@ハビエル:答えてくれてありがとう、しかし私は少し混乱しています。私はJavaで作業していますが、このコードはコンパイルされません。(condA && condB)エラー。&&は2 int秒間機能せず、ブール値は2つだけです。(condA & condB)正しい間は評価しますが、int java if(int)ではエラーとは言えないため、エラーも発生します。あなたは私が探しているものを理解する最初の人です-まさにその間違いの例
ディアシャ

長い時間でJavaを使用していない...してみてください(Boolean(condA) && Boolean(condB)) (私は考えてBoolean(x)いるtrue右、非ゼロの整数のため?)
ハビエル・

いいえ、@ Javier:intからboolean型にキャストできません。
ディアシャ

どう((condA!=0) && (condB!=0))
ハビエル

@Javierはコンパイルしますが、「誤り」は図示されなくなり if (((condA!=0) && (condB!=0))) { System.out.println("correct"); } if (((condA!=0) & (condB!=0))) { System.out.println("never executed?"); }、両方のprintステートメントを実行します。
ディアシャ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.