Javaのシフト演算の巧みな方法
4345 ワード
左シフト操作:x<xはbyte,short,char,int,long基本タイプであってもよく,n(変位量)はint型のみである
コンパイラの実行手順:
1)xがbyte,short,charタイプの場合、xをintに昇格させる.
2)xがbyte,short,char,intタイプである場合、nは再付与される(プロセスは、nの補符号の低い5ビットを取って10進数のint値に変換され、nに対して32モードを取る:n=n%32に相当する).
xがlong型である場合、nは再付与される(プロセスは、nの補符号をとる低6ビットが10進数のint値に再変換され、nに対して64モードをとる:n=n%64に相当する).
(intタイプが4バイト、すなわち32ビットであるため、32ビットを移動することは何の意味もない.longについてはモード64)
3)xをn桁左にシフトし、式全体に新しい値を生成する(xの値は変わらない).
<<は左シフト記号であり、列x<<1は、xの内容が左シフト1ビットである(xの内容は変化しない)
>>は記号ビット付きの右シフト記号であり、x>>1はxの内容が右シフト1ビットであり、先頭が1であれば1を補い、0は0を補い、(xの内容は変わらない).
>>>>は符号ビットを持たない右シフトであり、x>>>1はxの内容が右シフトし、先頭が0を補う(xの内容は変わらない)
補足:
Javaコード
output
1 2 4 8 16 32 64 128
output
40000000 20000000 10000000 8000000 4000000 2000000 1000000 800000
output
80000000 c0000000 e0000000 f0000000 f8000000 fc000000 fe000000 ff000000
上記の一般的な法則は間違っていないが、int型に対して、シフトのビット数は32を超えず、long型に対して、シフトのビット数は64を超えないという制限がある.次のテストを行います.
Javaコード
0 x 8000000は右シフト31ビット後、各ビットが1(すなわち−1)となったが、この考え方では、右シフト32ビットは当然−1であるが、右シフト32ビット後、得られた結果はまたこの数自体である.
int,long型データの左右シフトをテストしたところ,次のことが分かった.
Javaはシフト演算「a<|>>>b」の処理に対して、まずb mod 32||64演算を行い、aがint型であればmod 32、aがdouble型であればmod 64を取り、次に上述した汎用シフト演算規則を用いてシフトを行う.
ここまで、なぜBitSetクラスでは
この文は、jdkに詳しいProgramerが知っているので、1 L<(bitIndex%64)を書くのはjdkにとって余計です.
コンパイラの実行手順:
1)xがbyte,short,charタイプの場合、xをintに昇格させる.
2)xがbyte,short,char,intタイプである場合、nは再付与される(プロセスは、nの補符号の低い5ビットを取って10進数のint値に変換され、nに対して32モードを取る:n=n%32に相当する).
xがlong型である場合、nは再付与される(プロセスは、nの補符号をとる低6ビットが10進数のint値に再変換され、nに対して64モードをとる:n=n%64に相当する).
(intタイプが4バイト、すなわち32ビットであるため、32ビットを移動することは何の意味もない.longについてはモード64)
3)xをn桁左にシフトし、式全体に新しい値を生成する(xの値は変わらない).
<<は左シフト記号であり、列x<<1は、xの内容が左シフト1ビットである(xの内容は変化しない)
>>は記号ビット付きの右シフト記号であり、x>>1はxの内容が右シフト1ビットであり、先頭が1であれば1を補い、0は0を補い、(xの内容は変わらない).
>>>>は符号ビットを持たない右シフトであり、x>>>1はxの内容が右シフトし、先頭が0を補う(xの内容は変わらない)
補足:
Javaコード
- // : , 0
- for (int i = 0;i < 8 ;i++)
- System.out.print( (1 << i) + " ");
output
1 2 4 8 16 32 64 128
- // : , (int 32 ) 0, 0, 1, 1
- // 1
- for (int i = 0;i < 8 ;i++)
- System.out.print( Integer.toHexString(0x40000000 >> i) + " ");
output
40000000 20000000 10000000 8000000 4000000 2000000 1000000 800000
- // 1
- // 4 1000, 1 , 1100 c,
- for (int i = 0;i < 8 ;i++)
- System.out.print( Integer.toHexString(0x80000000 >> i) + " ");
output
80000000 c0000000 e0000000 f0000000 f8000000 fc000000 fe000000 ff000000
上記の一般的な法則は間違っていないが、int型に対して、シフトのビット数は32を超えず、long型に対して、シフトのビット数は64を超えないという制限がある.次のテストを行います.
Javaコード
- System.out.println(Integer.toHexString(0x80000000 >> 31));
- // output: ffffffff
- System.out.println(Integer.toHexString(0x80000000 >> 32));
- // output: 80000000
0 x 8000000は右シフト31ビット後、各ビットが1(すなわち−1)となったが、この考え方では、右シフト32ビットは当然−1であるが、右シフト32ビット後、得られた結果はまたこの数自体である.
int,long型データの左右シフトをテストしたところ,次のことが分かった.
Javaはシフト演算「a<|>>>b」の処理に対して、まずb mod 32||64演算を行い、aがint型であればmod 32、aがdouble型であればmod 64を取り、次に上述した汎用シフト演算規則を用いてシフトを行う.
ここまで、なぜBitSetクラスでは
- 1L << bitIndex
この文は、jdkに詳しいProgramerが知っているので、1 L<(bitIndex%64)を書くのはjdkにとって余計です.