算術右シフト
日本語 | 算術右ずらし |
英語 | arithmetic right shift、signed right shift |
ふりがな | さんじゅつみぎしふと |
フリガナ | サンジュツミギシフト |
右方向にビットシフトする際に、左端のビットには「シフト前の値」をセットする方法。
「>>演算子」によるビットシフト。
右ビットシフトを行う際の、左端のビット処理には2種類ある。
・算術右シフト
「シフト前の値をセットする」方法。左端のビットが0であれば0、1であれば1をセットする。
・論理右シフト
「常に0をセットする」方法。左端のビットに関わらず常に0をセットする。
算術右シフトは左端のビットが1の場合には1をセットする。
これは、プラスマイナスの「符号」が左端のビットにあり、このビットの値をそのまま残すことで「正負を維持する」ことができ、さらに「ビットシフトによる計算」ができるためである。
int型等の整数型は、左端のビットが「符号」を表すビットとなっている。0がプラス、1がマイナスである。
算術右シフトは左端のビットを維持するため、この符号も維持される。つまり、マイナスの値を算術右シフトした結果はマイナスとなる。
さらに、整数型のマイナスの値は「2の補数」という形式で表現されており、いわば0と1が逆の状態となる。そのため、マイナスの場合に左端から1を追加していくことで、プラスの時に0が追加されるのと同じ結果となる。
ビットシフトは「2進数形式で桁を減らす」ことになるため、その結果は「シフト数だけ2で割る」こととなる(ただし余りが出る場合もある)。
マイナスの値の場合、左端に1を追加していくことでこの計算を行うことができる。
つまり、算術右シフトを行うことで、マイナスの場合にも「シフト数だけ2で割る」という計算を行うことができる。
この「計算ができる」という点が「算術」の理由である。
算術右シフトはこのように「計算を行うためのビットシフト」である。
純粋に「ビットを移動したい」という場合には不便なため、その場合には「論理右シフト」を使用した方がいいだろう。
左方向は「<<演算子」による「左シフト」のみである。「算術左シフト」「論理左シフト」は存在しない。
符号のビットは左端にあり、右端のビットは単なる「2進数での一番小さい桁」である。そのため、「<<演算子」は常に0をセットする。「算術」「論理」といった違いが意味をなさないことになる。
「>>演算子」によるビットシフト。
右ビットシフトを行う際の、左端のビット処理には2種類ある。
・算術右シフト
「シフト前の値をセットする」方法。左端のビットが0であれば0、1であれば1をセットする。
・論理右シフト
「常に0をセットする」方法。左端のビットに関わらず常に0をセットする。
算術右シフトは左端のビットが1の場合には1をセットする。
これは、プラスマイナスの「符号」が左端のビットにあり、このビットの値をそのまま残すことで「正負を維持する」ことができ、さらに「ビットシフトによる計算」ができるためである。
int型等の整数型は、左端のビットが「符号」を表すビットとなっている。0がプラス、1がマイナスである。
算術右シフトは左端のビットを維持するため、この符号も維持される。つまり、マイナスの値を算術右シフトした結果はマイナスとなる。
さらに、整数型のマイナスの値は「2の補数」という形式で表現されており、いわば0と1が逆の状態となる。そのため、マイナスの場合に左端から1を追加していくことで、プラスの時に0が追加されるのと同じ結果となる。
ビットシフトは「2進数形式で桁を減らす」ことになるため、その結果は「シフト数だけ2で割る」こととなる(ただし余りが出る場合もある)。
マイナスの値の場合、左端に1を追加していくことでこの計算を行うことができる。
つまり、算術右シフトを行うことで、マイナスの場合にも「シフト数だけ2で割る」という計算を行うことができる。
この「計算ができる」という点が「算術」の理由である。
算術右シフトはこのように「計算を行うためのビットシフト」である。
純粋に「ビットを移動したい」という場合には不便なため、その場合には「論理右シフト」を使用した方がいいだろう。
左方向は「<<演算子」による「左シフト」のみである。「算術左シフト」「論理左シフト」は存在しない。
符号のビットは左端にあり、右端のビットは単なる「2進数での一番小さい桁」である。そのため、「<<演算子」は常に0をセットする。「算術」「論理」といった違いが意味をなさないことになる。
参考サイト
- (参考サイトはありません)
// Sample.java
public class Sample
{
public static void main( String[] args )
{
long l;
// -8を右に2ビットシフトします。
// 左端に1が入っていることを確認してください。
l = -8;
System.out.println( l );
outputLongBit( l );
// -8
// 1111111111111111111111111111111111111111111111111111111111111000
l = l >> 2;
System.out.println( l );
outputLongBit( l );
// -2
// 1111111111111111111111111111111111111111111111111111111111111110
// このように、>>演算子による「算術右シフト」を行うと、
// 符号が維持されます。
// さらに、シフト数だけ2で割った値になります。
// このように「計算」を行うために使用するため「算術右シフト」と
// いいます。
// 参考:>>>演算子による「論理右シフト」の場合。
l = -8;
l = l >>> 2;
System.out.println( l );
outputLongBit( l );
// 4611686018427387902
// 0011111111111111111111111111111111111111111111111111111111111110
// このように、左端のビットに0がセットされることで、
// 値としては変になりますが、ビットとしてはむしろ
// こちらの方が希望する結果でしょう。
}
/**
* long型変数をビット形式で出力します。
*/
private static void outputLongBit( long l )
{
// long型変数をビット形式で文字列化します。
String source = Long.toBinaryString( l );
// 左0埋めします。
StringBuffer strbuf = new StringBuffer();
for( int iF1 = source.length(); iF1 < 64; ++iF1 )
{
strbuf.append( "0" );
}
strbuf.append( source );
System.out.println( strbuf.toString() );
}
}
public class Sample
{
public static void main( String[] args )
{
long l;
// -8を右に2ビットシフトします。
// 左端に1が入っていることを確認してください。
l = -8;
System.out.println( l );
outputLongBit( l );
// -8
// 1111111111111111111111111111111111111111111111111111111111111000
l = l >> 2;
System.out.println( l );
outputLongBit( l );
// -2
// 1111111111111111111111111111111111111111111111111111111111111110
// このように、>>演算子による「算術右シフト」を行うと、
// 符号が維持されます。
// さらに、シフト数だけ2で割った値になります。
// このように「計算」を行うために使用するため「算術右シフト」と
// いいます。
// 参考:>>>演算子による「論理右シフト」の場合。
l = -8;
l = l >>> 2;
System.out.println( l );
outputLongBit( l );
// 4611686018427387902
// 0011111111111111111111111111111111111111111111111111111111111110
// このように、左端のビットに0がセットされることで、
// 値としては変になりますが、ビットとしてはむしろ
// こちらの方が希望する結果でしょう。
}
/**
* long型変数をビット形式で出力します。
*/
private static void outputLongBit( long l )
{
// long型変数をビット形式で文字列化します。
String source = Long.toBinaryString( l );
// 左0埋めします。
StringBuffer strbuf = new StringBuffer();
for( int iF1 = source.length(); iF1 < 64; ++iF1 )
{
strbuf.append( "0" );
}
strbuf.append( source );
System.out.println( strbuf.toString() );
}
}
// Sample.java public class Sample { public static void main( String[] args ) { long l; // -8を右に2ビットシフトします。 // 左端に1が入っていることを確認してください。 l = -8; System.out.println( l ); outputLongBit( l ); // -8 // 1111111111111111111111111111111111111111111111111111111111111000 l = l >> 2; System.out.println( l ); outputLongBit( l ); // -2 // 1111111111111111111111111111111111111111111111111111111111111110 // このように、>>演算子による「算術右シフト」を行うと、 // 符号が維持されます。 // さらに、シフト数だけ2で割った値になります。 // このように「計算」を行うために使用するため「算術右シフト」と // いいます。 // 参考:>>>演算子による「論理右シフト」の場合。 l = -8; l = l >>> 2; System.out.println( l ); outputLongBit( l ); // 4611686018427387902 // 0011111111111111111111111111111111111111111111111111111111111110 // このように、左端のビットに0がセットされることで、 // 値としては変になりますが、ビットとしてはむしろ // こちらの方が希望する結果でしょう。 } /** * long型変数をビット形式で出力します。 */ private static void outputLongBit( long l ) { // long型変数をビット形式で文字列化します。 String source = Long.toBinaryString( l ); // 左0埋めします。 StringBuffer strbuf = new StringBuffer(); for( int iF1 = source.length(); iF1 < 64; ++iF1 ) { strbuf.append( "0" ); } strbuf.append( source ); System.out.println( strbuf.toString() ); } }