Javaビット単位演算子

1. 概要

https://docs.oracle.com/javase/tutorial/java/nutsandbolts/opsummary.html [演算子]は、Java言語でデータと変数を操作するために使用されます。
このチュートリアルでは、Bitwise OperatorsとJavaでの動作について説明します。

2. ビット演算子

*ビット単位の演算子は、https://medium.com/coderscorner/number-systems-decimal-binary-octal-and-hexadecimal-5e567e55ab28 [binary digit]または入力値のビットで動作します。*整数型に適用できますcan– _long、int、short、char、_、および_byte._
さまざまなビット演算子を調べる前に、まずそれらがどのように機能するかを理解しましょう。
*ビット演算子は、10進数に相当するバイナリで動作し、指定された演算子に従ってビットごとに演算を実行します。*
  • まず、オペランドはバイナリ表現に変換されます

  • 次に、演算子が各2進数に適用され、結果が
    計算された

  • 最後に、結果は10進数表現に変換されます

    例で理解しましょう。 2つの_integersを取りましょう:_
int value1 = 6;
int value2 = 5;
次に、これらの数値にビット単位のOR演算子を適用します。
int result = 6 | 5;
この操作を実行するには、まずこれらの数値のバイナリ表現が計算されます:
Binary number of value1 = 0110
Binary number of value2 = 0101
次に、操作が各ビットに適用されます。 結果は、新しい2進数を返します。
0110
0101
-----
0111
最後に、結果__0111 __は、_7_と等しい10進数に変換されます。
result : 7
ビットごとの演算子は、ビットごとの論理演算子とビットごとのシフト演算子にさらに分類されます。 それぞれのタイプを見ていきましょう。

3. ビットごとの論理演算子

ビット単位の論理演算子は、AND(&)、OR(|)、XOR(^)、およびNOT(〜)です。

3.1. ビット単位のOR(|)

  • OR演算子は2つの整数の各2進数を比較し、どちらかが1の場合は1を返します。*

    これは||に似ていますブール値とともに使用される論理演算子。 2つのブール値を比較すると、どちらかが_trueの場合、結果は_true_です。同様に、どちらかが1の場合、出力は1です。
    前のセクションでこの演算子の例をみました:
@Test
public void givenTwoIntegers_whenOrOperator_thenNewDecimalNumber() {
    int value1 = 6;
    int value2 = 5;
    int result = value1 | value2;
    assertEquals(7, result);
}
この操作のバイナリ表現を見てみましょう。
0110
0101
-----
0111
ここで、OR、0、および0を使用すると0になり、少なくとも1との組み合わせは1になります。

3.2. ビット単位AND(&)

  • AND演算子は、2つの整数の各2進数を比較し、両方が1の場合は1を返し、そうでない場合は0を返します。*

    これは、_boolean_値を持つ&&演算子に似ています。 2つの_booleans_の値が_true_の場合、&&演算の結果は_true._です。
    上記と同じ例を使用してみましょう。ただし、|の代わりに&演算子を使用します。オペレーター:
@Test
public void givenTwoIntegers_whenAndOperator_thenNewDecimalNumber() {
    int value1 = 6;
    int value2 = 5;
    int result = value1 & value2;
    assertEquals(4, result);
}
この操作のバイナリ表現も見てみましょう。
0110
0101
-----
0100
_0100_は10進数で_4_であるため、結果は次のようになります。
result : 4

3.3. ビット単位XOR(^)

  • XOR演算子は、2つの整数の各2進数を比較し、比較されたビットが両方とも異なる場合、1を返します。*これは、両方の整数のビットが1または0の場合、結果は0になることを意味します。それ以外の場合、結果は1になります。

@Test
public void givenTwoIntegers_whenXorOperator_thenNewDecimalNumber() {
    int value1 = 6;
    int value2 = 5;
    int result = value1 ^ value2;
    assertEquals(3, result);
}
そして、バイナリ表現:
0110
0101
-----
0011
__0011 __は10進数で3なので、結果は次のようになります。
result : 3

3.4. ビット単位COMPLEMENT(〜)

*ビット単位の否定演算子または補数演算子は、単に入力値の各ビットの否定を意味します。 整数は1つだけで、!と同等です。 オペレーター。*
この演算子は、整数の各2進数を変更します。つまり、すべて0が1になり、すべて1が0になります。 です! 演算子は_boolean_値に対しても同様に機能します。_boolean_値を_true_から_false_に、またはその逆に反転します。
ここで、10進数の補数を見つける方法を例で理解しましょう。
value1 = 6の補完を行いましょう:
@Test
public void givenOneInteger_whenNotOperator_thenNewDecimalNumber() {
    int value1 = 6;
    int result = ~value1;
    assertEquals(-7, result);
}
バイナリの値は次のとおりです。
value1 = 0000 0110
補数演算子を適用すると、結果は次のようになります。
0000 0110 -> 1111 1001
これは、10進数の6の1の補数です。 また、最初の(左端の)ビットは2進数で1であるため、格納される数値の符号は「負」であることを意味します。
ここで、数値は2の補数として保存されるため、まずその2の補数を見つけてから、結果の2進数を10進数に変換する必要があります。
1111 1001 -> 0000 0110 + 1 -> 0000 0111
最後に、0000 0111は10進数で7です。 上記のように符号ビットが1だったため、結果の答えは次のとおりです。
result : -7

3.5. ビット演算子テーブル

これまで見てきた演算子の結果を比較表にまとめてみましょう。
A    B   A|B A&B A^B ~A
0   0   0   0   0   1
1   0   1   0   1   0
0   1   1   0   1   1
1   1   1   1   0   0

4.  ビット単位のシフト演算子

*バイナリシフト演算子は、シフト演算子に基づいて入力値のすべてのビットを左または右にシフトします。*
これらの演算子の構文を見てみましょう。
value <operator> <number_of_times>
式の左側はシフトされる整数であり、式の右側はシフトされる必要がある回数を示します。
ビット単位のシフト演算子は、ビット単位の左シフト演算子とビット単位の右シフト演算子としてさらに分類されます。

4.1. 符号付き左シフト[<<]

*左シフト演算子は、オペランドの右側で指定された回数だけビットを左にシフトします。 左シフトの後、右側の空のスペースは0で埋められます。*
注意すべきもう1つの重要な点は、* 1で数値をシフトすることは、2を乗算することと同等である、または一般に、number_n_ positionsで数値を左にシフトすることは、2 ^ __ n__で乗算することと同等であることです*
入力値として値12を取りましょう。
ここで、左に2箇所(12 << 2)移動し、最終結果がどうなるかを確認します。
12に相当するバイナリは00001100です。 左に2桁シフトした後、結果は00110000になり、これは10進数で48に相当します。
@Test
public void givenOnePositiveInteger_whenLeftShiftOperator_thenNewDecimalNumber() {
    int value = 12;
    int leftShift = value << 2;
    assertEquals(48, leftShift);
}
これは負の値に対しても同様に機能します。
@Test
public void givenOneNegativeInteger_whenLeftShiftOperator_thenNewDecimalNumber() {
    int value = -12;
    int leftShift = value << 2;
    assertEquals(-48, leftShift);
}

4.2. 署名付き右シフト[>>]

*右シフト演算子は、すべてのビットを右にシフトします。*左側の空のスペースは、入力番号に応じて埋められます。
  • *入力番号が負の場合、左端のビットが1の場合、
    空のスペースは1 *で埋められます

  • *入力番号が正で、左端のビットが0の場合、
    空のスペースは0 *で埋められます

    12を入力として使用して例を続けましょう。
    ここで、2つ右に移動し(12 >> 2)、最終結果を確認します。
    入力数は正であるため、2桁右にシフトした後、結果は0011になり、これは10進数で3です。
@Test
public void givenOnePositiveInteger_whenSignedRightShiftOperator_thenNewDecimalNumber() {
    int value = 12;
    int rightShift = value >> 2;
    assertEquals(3, rightShift);
}
また、負の値の場合:
@Test
public void givenOneNegativeInteger_whenSignedRightShiftOperator_thenNewDecimalNumber() {
    int value = -12;
    int rightShift = value >> 2;
    assertEquals(-3, rightShift);
}

4.3。 符号なし右シフト[>>>]

この演算子は、符号付き右シフト演算子に非常に似ています。 *唯一の違いは、数値が正か負かに関係なく、左側の空のスペースが0で埋められることです。したがって、結果は常に正の整数になります。
同じ12の値を右にシフトしましょう:
@Test
public void givenOnePositiveInteger_whenUnsignedRightShiftOperator_thenNewDecimalNumber() {
    int value = 12;
    int unsignedRightShift = value >>> 2;
    assertEquals(3, unsignedRightShift);
}
そして今、負の値:
@Test
public void givenOneNegativeInteger_whenUnsignedRightShiftOperator_thenNewDecimalNumber() {
    int value = -12;
    int unsignedRightShift = value >>> 2;
    assertEquals(1073741821, unsignedRightShift);
}

5. ビット演算子と論理演算子の違い

ここで説明したビット単位の演算子と、一般的に知られている論理演算子にはいくつかの違いがあります。
まず、*論理演算子は_boolean_式*で動作し、_boolean_値(_true_または_falseのいずれか)を返します。整数。
また、論理演算子は常に最初の_boolean_式を評価し、その結果と使用する演算子に応じて、2番目の式を評価する場合と評価しない場合があります。 一方、*ビット演算子は常に両方のオペランドを評価します*。
最後に、論理演算子は複数の条件に基づいて決定を下す際に使用されますが、ビットごとの演算子はビットに対して機能し、ビットごとの演算を実行します。

6. ユースケース

ビット演算子のいくつかの潜在的な使用例は次のとおりです。
  • ヘッダーの個々のビットが添付された通信スタック
    データに重要な情報を示します

  • 組み込みシステムでは、1ビットだけを設定/クリア/トグルする
    残りのビットを変更しない特定のレジスタ

  • XOR演算子を使用して安全性の問題のためにデータを暗号化するには

  • データをある表現からに変換することによるデータ圧縮
    もう1つは、使用されるスペースの量を減らすためです

7.  結論

このチュートリアルでは、ビット演算子のタイプと、それらが論理演算子とどのように異なるかについて学びました。 また、それらの潜在的なユースケースもいくつか見ました。
この記事のすべてのコード例は、https://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java [GitHubで]から入手できます。