2009年07月14日

【1日1Java】シフト演算子の説明

Integerクラスのビット関連の中身を徐々に漁ってみたいので、
下準備としてシフト演算子に関するお話


// JRE 1.6.0_07
// シフト演算子
// >> と >>>, << と <<< の違い
// tag bit

// >> は n ビット右シフトをします
// 右にシフトすると、一番左の値がなくなってしまいます
// そこには、これまで一番左にあった値と同じ値(正なら0, 負なら1)が
// 入ります

// 例、-100を1ビット右にシフトする
// 1ビット右シフトする = 2で割ると同義なので、-50になります
System.out.println( -100 >> 1 );
 // => -50

// -100 と -50の2進数表記を見比べてみる
// -100
System.out.println( Integer.toBinaryString( -100 ) );
  // => 11111111111111111111111110011100
// -50
System.out.println( Integer.toBinaryString( -50 ) );
  // => 11111111111111111111111111001110
// 見ての通り、0の位置が1つずつ右にずれています

// 正の数の場合は、一番左のビットが0なので、
// シフトすると一番左に0が付きます

// 100
System.out.println( Integer.toBinaryString( 100 ) );
  // => 00000000000000000000000001100100
// 100 >> 1
System.out.println( Integer.toBinaryString( 100 >> 1 ) );
  // => 00000000000000000000000000110010

// これが >>> だと、それまでの一番左のビットの値に関係なく、0が入ります
System.out.println( Integer.toBinaryString( -100 ) );
  // => 11111111111111111111111110011100
System.out.println( Integer.toBinaryString( -100 >>> 1 ) );
  // => 01111111111111111111111111001110
// ちなみに -100 >>> 1 の10進数表記はこんな漢字
System.out.println( -100 >>> 1 );
  // => 2147483598

// -100 >> 1 が ( -100 / 2 ) と同義だったんい比べて、
// 随分と(10進数的に)無関係に見える値が出てきます

// x >>> 31 とすると、これまで一番左側にいたビットが
// 一番右側に移動して、他は全て0で埋められるので、
// 正か0なら0、負なら1という値が取れることになります
System.out.println( 25982059 >>> 31 );
  // => 0
System.out.println( -25982059 >>> 31 );
  // => 1

// x >> 31 とすると、これまで一番左に居た値で
// 全32ビットが埋められることになるので、
// 正か0なら0、負なら-1になります
System.out.println( 45398053 >> 31);
  // => 0
System.out.println( -45398053 >> 31);
  // => -1

// では、x >>> 32 はいくつになるでしょう
// 一瞬、0になりそうなイメージが浮かぶかもしれませんが、
// 答えは x、つまり実行前と同値です
System.out.println( 39285 >>> 32 );
  // => 39285
System.out.println( -39285 >>> 32 );
  // => -39285

// x >>> 33 はいくつになるでしょう
// 答えは x >>> (33 - 32) になります
System.out.println( 100 >>> 33 );
// => 50

// どうやらintの桁数(32bit)を超えると1回転するようです

// なのでlong(64bit)にすれば、先ほどの結果は0になります
System.out.println( (long)39285 >>> 32 );
  // => 0