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コード

  
  
  
  
  1. //  :  , 0   
  2. for (int i = 0;i < 8 ;i++)   
  3. System.out.print( (1 << i) + " "); 

output
1 2 4 8 16 32 64 128

  
  
  
  
  1. //  :  , (int 32 ) 0, 0, 1, 1   
  2. //  1    
  3. for (int i = 0;i < 8 ;i++)   
  4. System.out.print( Integer.toHexString(0x40000000 >> i) + " "); 

output
40000000 20000000 10000000 8000000 4000000 2000000 1000000 800000

  
  
  
  
  1.  //  1    
  2. //  4 1000,  1 , 1100 c,   
  3. for (int i = 0;i < 8 ;i++)   
  4. System.out.print( Integer.toHexString(0x80000000 >> i) + " "); 

output
80000000 c0000000 e0000000 f0000000 f8000000 fc000000 fe000000 ff000000
上記の一般的な法則は間違っていないが、int型に対して、シフトのビット数は32を超えず、long型に対して、シフトのビット数は64を超えないという制限がある.次のテストを行います.
Javaコード

  
  
  
  
  1. System.out.println(Integer.toHexString(0x80000000 >> 31));   
  2. // output: ffffffff   
  3. System.out.println(Integer.toHexString(0x80000000 >> 32));   
  4. // 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クラスでは

  
  
  
  
  1. 1L << bitIndex 

この文は、jdkに詳しいProgramerが知っているので、1 L<(bitIndex%64)を書くのはjdkにとって余計です.