2009年07月13日

【1日1Java】Integer.signumでビットの勉強

JavaのInteger.signumで使用されているロジックを見ながらビット演算の勉強


// JRE 1.6.0_07
// java.lang.Integer.signum
// Integerクラスのsignumのロジックを見てみる
// tag bit signum

// ※注意事項
// Integer.toBinaryStringを使用した場合は、
// 最も左にある1より左方の0は省略されますが、
// 見づらいので、0埋めされてるかのように出力結果を書いています

// signumは、それが正数か負数かを判定する
// 正数なら「1」、0なら「0」、負数なら「-1」を返す
System.out.println( Integer.signum( 100 ) );
  // => 1
System.out.println( Integer.signum( 0 ) );
  // => 0
System.out.println( Integer.signum( -100 ) );
  // => -1

// signumの中の表記はこんな風になっています
// return (i >> 31) | (-i >>> 31);

// (i >> 31)は、31個シフトすることで、正なら00000(ry, 負なら1111(ryになります
// 0の場合はもちろん0です
System.out.println( Integer.toBinaryString( 100 >> 31 ) );
  // => 00000000000000000000000000000000
System.out.println( Integer.toBinaryString( -100 >> 31 ) );
  // => 11111111111111111111111111111111

// -iは、iの2の補数になるので、0の場合以外は先頭ビットが入れ替わります
System.out.println( Integer.toBinaryString( 100 * -1 ) );
  // => 11111111111111111111111110011100
System.out.println( Integer.toBinaryString( -100 * -1 ) );
  // => 00000000000000000000000001100100

// >>> は左側のビットは0埋めされるので、
// (-i >>> 31) は、一番左端のビットが右端に来て、残りのビットは全て0になります
// つまり、正なら1、負なら0、0なら0になります
System.out.println( Integer.toBinaryString( -1 * 100 >>> 31 ) );
  // => 1
System.out.println( Integer.toBinaryString( -1 * -100 >>> 31 ) );
  // => 0
System.out.println( Integer.toBinaryString( -1 * 0 >>> 31 ) );
  // => 0

// 最後にもう1度、signumのロジックを見てみましょう
// (i >> 31) | (-i >>> 31)

// 上で求めた値を | しています
// つまり、正数だった場合は、「 0 | 1 = 1 」になります

// 負数だった場合は、「11111111111111111111111111111111 | 0 = -1」になります
// 111(ryは、-1の2進数表記です
System.out.println( Integer.toBinaryString( -1 ) );
  // => 11111111111111111111111111111111

// 最後に0の場合は、「 0 | 0 」なので、もちろん0になります


// 興味があったので、三項演算子でやった場合と実行時間を比較してみる
long ll = System.nanoTime();
for( int i = 0; i < 10000; i++ ) {
    int j = i == 0 ? 0 : i > 0 ? 1 : -1;
}
// 三項演算子で判定した場合の実行時間
System.out.println( System.nanoTime() - ll );
  // => 419621

long l = System.nanoTime();
for( int i = 0; i < 10000; i++ ) {
    int j = (i >> 31) | (-i >>> 31);
}
// signumの実行時間
System.out.println( System.nanoTime() - l );
  // => 662615

// ありゃ、signumの方が遅い・・・・