<<2.演算子と制御文の目次
ビット演算
問題25(難易度:2)                                2004年12月23日
次をコンパイル、実行すると、結果はどうなるか。下から選べ。

      1:  int a = -1, b, c, d;
      2:    b = a >> 31;
      3:   c = a >>> 31;
      4:    d = a << 31;
      5:    System.out.println(b + " " + c + " " + d);
  A: 1 1 2147483648 と出力される。
  B: -1 -1 -2147483648 と出力される。
  C: -1 1 -2147483648 と出力される。
  D: 1 1 -2147483648 と出力される。
解説
 ビット演算は、byte、short、int、long、charの整数型について行うことができます。整数は内部で2進数で記憶されているのはよいでしょうか。問題はaの値が−1で、このビットパターンがわからないと解けません。

 以下−10のビットパターンを求める方法を示しますが、ご存知の方は飛ばしてください。
 まず10の2進表示を考えます。こんな方法昔やりませんでしたか?
10を2で割って5、その余りを5の右に書きます。0ですね。次は5を2で割って2、その余り1を2の右に書きます。2を2で割って1、余りは0、出てきた1と0を矢印の順で並べます。1010、これが10の2進数です。意味は次のとおり。

(1010) = 1×2+0×2+1×2+0×2
       = 10

つまり32ビットのint型に10を代入すると、
 00000000 00000000 00000000 00001010
となるわけです。
 では−10はどうなるかです。
 10のビットパターンを右から見ていき、最初に1が現れるまではそのままコピーします。水色の部分です。そこから先はすべてのビットを逆転させます。赤い矢印です。1ならば0、0ならば1にします。これで−10のできあがり。どうですか、10とー10の2進数同士を足してみてください。繰り上がって0になるはずです。

 では−1はどうなるでしょうか。1はもちろん
    00000000 00000000 00000000 00000001
です。上の法則から−1は
    11111111 11111111 11111111 11111111
となります。最上位のビット(左端のビット)を見れは、負の数かどうかがわかります。0ならば正、1ならば負となります。これで前座は終わり。

 シフト演算子には「>>」「>>>」「<<」の3種類があります。「>>」と「>>>」は右にシフト、「<<」は左にシフトです。矢印←→の頭のようです。CやC++には「>>>」はありません。

 まず「>>」は右にシフトしますが、シフトした分、新しく左側から補われるビットは、元のビットパターンの最上位ビットと同じものになります。つまり負の数はシフトしても負のままということです。
 では−1を1ビット分シフトした場合を考えましょう。図にあるように、赤のビットが1なので、全体を右に1ビットずらした後の水色のところには1が入ります。つまり何も変わらないわけです。31ビット分シフトしても、同じことです。よって「a>>31」の結果は−1になるはずです。
 次は「>>>」です。これは上の「>>」と同じ右シフトですが、左側からは0が補われます。次の図のようになります。「a>>>31」は右側31ビット分が0になり、結果は1になるはずです。もう答えはCであることがわかりました。
 最後に「<<」。これは左シフトで、右からは必ず0が補われます。「<<<」はありません。「a<<31」は次の図のようになり、負の数、それもintであらわせる最小値になることがわかります。
解答 C
問題26(難易度:2)                             2004年12月24日
次をコンパイル、実行すると、結果はどうなるか。下から選べ。
      1:  int a = 1, b, c, d;
      2:    b = a >> 32;
      3:    c = a >>> 64;
      4:    d = a << 33;
      5:    System.out.println(b + " " + c + " " + d);
  A: 1 1 2 と出力される。
  B: 0 0 0 と出力される。
  C: 1 0 2147483648 と出力される。
  D: コンパイルエラーになる。
  E: 実行時に例外が発生する。
解説
 例えば4行目は、、シフト演算子の左がint型、右がint型の長さ32より大きい33なので、aの中のビットがすべて左へこぼれ出て結果は0になるのでは..と思われた方、残念。int型についてのシフトは、シフト幅が32以上の場合、32で割った余りが実際のシフト幅になる、という決まりがあるのです。33ですから余りは1、つまり「a<<1」と同じ、結果は2になります。
 2行目と3行目のシフト幅はどちらも0になるので、bもcもaの値がそのまま入ります。よってどちらも1。以上から正解はAになります。

 ところでlong型のシフトの場合はどうなるのでしょうか。long型の長さは64ビットなので、上の説明の32を64にすべて置き換えればOKです。

解答 A
問題27(難易度:2)                                2004年12月25日
次をコンパイル、実行すると、結果はどうなるか。下から選べ。
        1:  int a = 10, b = 12, c, d, e, f;
        2:    c = a & b;
        3:    d = a | b;
        4:    e = a ^ b;
        5:    f = ~a;
        6:    System.out.println(c + " " + d + " " + e + " " + f);

  A: 14 8 6 11 と出力される。
  B: 14 8 9 -11 と出力される。
  C: 8 14 9 11 と出力される。
  D: 8 14 6 -11 と出力される。
解説
 ビット演算に使える演算子は、問題25のシフト演算子3つの他に、「&」「|」「^」「~」があります。どれも整数型についての演算を行います。また「~」以外はboolean型の演算でも使用できます。(→問題22問題23) 

  「&」は、対応するビットが1と1のときのみ1、それ以外は0になります。「|」は0と0のときのみ0、「^」は1と0のとき1になります。また「~」はビットを反転させます。次に各演算子の働きを示します。
 では問題を考えましょう。まず10と12のビットパターンを求めます。そして対応するビットから結果を求めましょう。cには(1000)で2=8が入ります。

                a 00000000 00000000 00000000 00001010
               b 00000000 00000000 00000000 00001100

            a&b 00000000 00000000 00000000 00001000

 同様にd、e、fも求めましょう

               a 00000000 00000000 00000000 00001010
               b 00000000 00000000 00000000 00001100

            a|b 00000000 00000000 00000000 00001110


               a 00000000 00000000 00000000 00001010
               b 00000000 00000000 00000000 00001100

             a^b 00000000 00000000 00000000 00000110


               a 00000000 00000000 00000000 00001010              

             ~a   11111111 11111111 11111111 11110101

 dには(1110)=2+2+2=14、eには(110)=2+2=6が入ります。

 ではfの値はどうなるのでしょうか。最上位ビットが1なので、負の数になります。絶対値は
        00000000 00000000 00000000 00001011
になるはずです。(→問題25)これは(1011)=2+2+1=11。よってfには−11が入ります。正解はD。

解答 D
問題28(難易度:2)                              2004年12月26日
下の中から、文法的に正しいものを選べ。ただし変数bとx、yは次のとおり宣言されているものとする。
        boolean b;
        int x = 1;
        long y = 2;

  A: b = !x;
  B: b = ~x;
  C: y = x & y;
  D: b = x && y;
  E: y = ^y;
 まずA。「!」は論理演算子の否定なので、その次にはboolean型が来なければならないのに、xはint型なので×。
 Bの「~」はビット演算子のビットを反転する演算子なので、次にint型のxが来るのは正しいです。でもその結果をboolean型に代入することは間違え。
 Cの「&」はビット演算子として使用できるので、左右がintやlongの整数型なのは○。結果をlong型に入れているのも大丈夫なので、これが正しいです。
 Dの「&&」は論理演算子なので、intのxとlongのyが左右にあるため×。
 Eの「^」はビット演算子で左右に整数型がなければならないため×。

解答 C
 <<2.演算子と制御文の目次|次問題>>
Copyright (c) 2004 Nagi Imai All Rights Reserved..