JavaRush /Java Blog /Random-JA /Java でのビット単位の演算

Java でのビット単位の演算

Random-JA グループに公開済み
「ビート」という言葉をご存知の方も多いのではないでしょうか。そうでない場合は、それを知りましょう :) ビットは、コンピューター内の情報の最小測定単位です。その名前は英語の「binary digit」-「二進数」に由来しています。ビットは、1 または 0 の 2 つの数値のいずれかとして表現できます。1 と 0 に基づく特別な数値体系、つまり 2 進数があります。ここでは数学の密林には立ち入りません。Java のあらゆる数値はバイナリ形式に変換できることだけを述べておきます。これを行うには、ラッパー クラスを使用する必要があります。 ビット単位の演算 - 1たとえば、数値に対してこれを行う方法は次のとおりですint
public class Main {

   public static void main(String[] args) {

       int x = 342;
       System.out.println(Integer.toBinaryString(x));
   }
}
コンソール出力:

101010110
1010 10110 (読みやすくするためにスペースを追加しました) は、2 進数の 342 です。実際には、この数値を個々のビット (0 と 1) に分割しました。これらを使用して、ビット単位と呼ばれる演算を実行できます。
  • ~— ビット単位の「NOT」演算子。

これは非常に簡単に動作します。数値の各ビットを調べて、その値を逆に、0 から 1、1 から 0 に変更します。これを数値 342 に適用すると、次のようになります。 101010110 は、バイナリの数値 342 です。 010101001 は、式 ~342 の結果です。 ただし、int 変数は 4 バイト必要なので、つまり、32 ビット、実際には、変数内の数値は次のように格納されます。 00000000 00000000 00000001 01010110- Java の int 型変数内の数値 342 11111111 11111111 11111110 10101001- Java の式 ~342 の結果 これを実際に実行してみましょう。
public class Main {

   public static void main(String[] args) {

       int x = 342;
       System.out.println(Integer.toBinaryString(~x));
   }
}
コンソール出力:
11111111111111111111111010101001
  • &— ビット演算子「AND」

ご覧のとおり、論理「AND」( &&) と非常によく似た書き方になっています。&&覚えているとおり、演算子はtrue両方のオペランドが true の場合にのみ戻ります。ビットワイズも&同様の方法で機能し、2 つの数値をビットごとに比較します。この比較の結果が 3 番目の数値です。たとえば、数値 277 と 432 を考えてみましょう。 100010101 - バイナリ形式の数値 277 110110000 - バイナリ形式の数値 432 次に、演算子は、上位の&数値の最初のビットと下位の数値の最初のビットを比較します。これは「AND」演算子であるため、両方のビットが 1 に等しい場合にのみ、結果は 1 になります。それ以外のすべての場合、結果は 0 になります。 100010101 & 110110000 _______________ 100010000 - 作業の結果& まず最初のビットを比較します。 2 つの数値を相互に結合し、次に 2 番目のビット、3 番目のビットなどを結合します。ご覧のとおり、数値内の両方のビットが 1 に等しいケースは 2 つだけでした (1 番目と 5 番目のビット)。他のすべての比較の結果は 0 でした。したがって、最終的には 100010000 という数値が得られました。10 進法では、これは数値 272 に相当します。次を確認してみましょう。
public class Main {

   public static void main(String[] args) {
       System.out.println(277&432);
   }
}
コンソール出力:

272
  • |- ビット単位の「OR」。動作原理は同じです。2 つの数値をビットごとに比較します。ここでのみ、ビットの少なくとも 1 つが 1 に等しい場合、結果は 1 になります。同じ数値 277 と 432 を見てみましょう。
100010101 | 110110000 _______________ 110110101 - 作業の結果| ここでは結果が異なります: 両方の数値でゼロだったビットのみがゼロのままです。作業の結果は、数値 110110101 です。10 進法では、数値 437 に対応します。確認してみましょう。
public class Main {

   public static void main(String[] args) {
       System.out.println(277|432);
   }
}
コンソール出力:

437
すべて正確に数えました!:)
  • ^- ビット単位の排他的 OR (XOR とも呼ばれます)
私たちはこれまでそのようなオペレーターに遭遇したことがありません。しかし、それについては何も複雑なことはありません。通常の「または」のように見えます。違いは 1 つあります。通常の「or」は、true少なくとも 1 つのオペランドが true の場合に戻り値を返します。ただし、必ずしも 1 つである必要はなく、両方が存在する場合にtrueは結果が得られますtrue。ただし、排他的「or」はtrueオペランドの 1 つが true の場合にのみ返されます。true両方のオペランドが true の場合、通常の「or」は (「少なくとも 1 つが true」)を返しますが、排他的 or は を返しますfalse。それがエクスクルーシブと呼ばれる理由です。これまでのビット演算の原理を理解していれば、おそらく 277^432 演算を自分で簡単に実行できるでしょう。でも、もう一度一緒に考えてみましょう :) 100010101 ^ 110110000 _______________ 010100101 - 作業の結果^ これが私たちの結果です。両方の数値で同じビットは 0 を返しました (「いずれか」の式は機能しませんでした)。しかし、0-1または1-0でペアを形成したものは、最終的にはユニットになりました。その結果、数値 010100101 が得られました。10 進法では、これは数値 165 に相当します。計算が正しく行われたかどうかを確認してみましょう。
public class Main {

   public static void main(String[] args) {
       System.out.println(277^432);
   }
}
コンソール出力:

165
素晴らしい!すべては私たちが考えていたとおりです:) ここで、ビットシフトと呼ばれる操作について学びましょう。原則として、名前自体がそれを物語っています。いくつかの数値を取得して、そのビットを左右に移動します:) それがどのようになるかを見てみましょう:

左にシフト

ビットの左シフトは符号で示されます<< 。 例:
public class Main {

   public static void main(String[] args) {
       int x = 64;//meaning
       int y = 3;//quantity

       int z = (x << y);
       System.out.println(Integer.toBinaryString(x));
       System.out.println(Integer.toBinaryString(z));
   }
}
この例では、数値をx=64値と呼びます。私たちがシフトするのはその部分です。ビットを左にシフトします (これは符号の方向によって決定できます<<) 2 進法では、数値 64 = 1000000 この数値はy=3数量と呼ばれます。quantity は、「数値のビットを右/左に何ビットシフトする必要がありますかx?」という質問に答えます。この例では、左に 3 ビットシフトします。シフトプロセスをより明確にするために、画像を見てみましょう。この例では、int 型の数値を使用します。Intはコンピュータのメモリの 32 ビットを占有します。元の数値 64 は次のようになります。 ビット単位の演算 - 2そして、言葉の文字通りの意味で、各ビットを取り出して 3 セル分左にシフトします。 ビット演算 - 3これが得られた結果です。ご覧のとおり、すべてのビットがシフトされ、さらに 3 つのゼロが範囲外から追加されています。3 - 3 だけシフトしたためです。10 ずつシフトすると、10 個のゼロが追加されます。したがって、この式はx << y「数値хy セルのビットを左にシフトする」ことを意味します。式の結果は 1000000000 という数値になり、10 進法では 512 に相当します。次を確認してみましょう。
public class Main {

   public static void main(String[] args) {
       int x = 64;//meaning
       int y = 3;//quantity

       int z = (x << y);
       System.out.println(z);
   }
}
コンソール出力:

512
それは正しい!理論的には、ビットは無制限にシフトできます。しかし、番号があるのでint、使用できるセルは 32 個だけです。これらのうち、7 つはすでに 64 (1,000,000) という数字によって占められています。したがって、たとえば左に 27 シフトすると、唯一のユニットが範囲外になり「上書き」されます。ゼロだけが残ります!
public class Main {

   public static void main(String[] args) {
       int x = 64;//meaning
       int y = 26;//quantity

       int z = (x << y);
       System.out.println(z);
   }
}
コンソール出力:

0
予想通り、1 つは 32 ビット セルを超えて消えてしまいました。ゼロのみで構成される 32 ビットの数値が得られました。 ビット演算 - 4当然、10 進法では 0 に相当します。左シフトを覚えるための簡単なルール: 左シフトするたびに、数値は 2 倍されます。たとえば、ビットのある画像なしで式の結果を計算してみましょう 111111111 << 3 。数値 111111111 に 2 を 3 回掛けます。その結果、888888888 が得られます。コードを書いて確認してみましょう。
public class Main {

   public static void main(String[] args) {
       System.out.println(111111111 << 3);
   }
}
コンソール出力:

888888888

右シフト

それらは という記号で示されています>>。彼らは同じことをしますが、反対方向にのみ行います。:) 車輪の再発明はせずに、同じ数値 int 64 を使ってこれを実行してみましょう。
public class Main {

   public static void main(String[] args) {
       int x = 64;//meaning
       int y = 2;//quantity

       int z = (x >> y);
       System.out.println(z);
   }
}
ビット単位の演算 - 5ビット演算 - 6右に 2 シフトした結果、数値の 2 つの極端なゼロが範囲外になり、消去されました。数値 10000 が得られました。これは、10 進法では数値 16 に対応します。コンソールへの出力:

16
右シフトを覚えるための簡単なルール: 各右シフトを 2 で割って、余りを破棄します。たとえば、 35 >> 2 35 を 2 で 2 回割り、余りを切り捨てる 35/2 = 17(余り 1 を捨てる) 17:2 = 8(余り 1 を捨てる) 合計は35 >> 28 に等しくなる必要があることを意味します。
public class Main {

   public static void main(String[] args) {
       System.out.println(35 >> 2);
   }
}
コンソール出力:

8

Java での操作の優先順位

コードを書いたり読んだりすると、複数の操作が同時に実行される式に遭遇することがよくあります。それらがどのような順序で実行されるかを理解することが非常に重要です。そうしないと、予期しない結果が生じる可能性があります。Java には多くの操作があるため、それらはすべて特別なテーブルに分けられています。

演算子の優先順位

オペレーター 優先順位
接尾辞 expr++ expr--
単項 ++expr --expr +expr ~ !
乗法 * / %
添加剤 + -
シフト << >> >>>
関連した < > <= >=インスタンスの
平等 == !=
ビットごとの AND &
ビット単位の排他的論理和 ^
ビットごとの包含的 OR |
論理積 &&
論理和 ||
三項 ? :
割り当て = += -= *= /= %= &= ^= |= <<= >>= >>>=
すべての操作は、優先順位を考慮して左から右に実行されます。たとえば、次のように書くと、 int x = 6 - 4/2; まず除算演算 (4/2) が実行されます。彼女は 2 番目ですが、優先順位は高くなります。括弧または角括弧を使用すると、優先度が最大に変更されます。あなたはおそらく学校でこれを覚えているでしょう。たとえば、これらを式に追加すると、 int x = (6 - 4)/2; 括弧内で計算されるため、減算が最初に実行されます。&&表からわかるように、論理演算子の優先順位はかなり低くなります。したがって、ほとんどの場合、最後に実行されます。例: boolean x = 6 - 4/2 > 3 && 12*12 <= 119; この式は次のように実行されます。
  • 4/2 = 2

    boolean x = 6 - 2 > 3 && 12*12 <= 119;
  • 12*12 = 144

    boolean x = 6 - 2 > 3 && 144 <= 119;
  • 6-2 = 4

    boolean x = 4 > 3 && 144 <= 119;
  • 次に比較演算子が実行されます。

    4 > 3 = true

    boolean x = true && 144 <= 119;
  • 144 <= 119 = false

    boolean x = true && false;
  • そして最後に、最後の演算子が実行されます&&

    boolean x = true && false;

    boolean x = false;

    +たとえば、加算演算子 ( ) は比較演算子!=(「等しくない」) よりも優先されます。

    したがって、式では次のようになります。

    boolean x = 7 != 6+1;

    最初に演算 6+1 が実行され、次にチェック 7!=7 (false) が実行され、最後に結果がfalse変数に代入されますx。一般に、割り当てはすべての操作の中で最も優先順位が低くなります。表を見てください。

ふう!私たちの講義は長かったですが、よく頑張りました!この講義と前の講義の一部が完全に理解できていない場合でも、心配しないでください。これらのトピックについては、今後何度か触れます。以下に役立つリンクをいくつか示します。
  • 論理演算子- JavaRush は論理演算について講義します。すぐにはアクセスできませんが、今読んでも問題ありません。
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION