2の補数
日本語 | 2の補数 |
英語 | two's complement |
ふりがな | にのほすう |
フリガナ | ニノホスウ |
整数の、各ビットを反転して1を足した値。
2進数の各ビットについて、「0であれば1、1であれば0」に変換したものに、1を足した値を「2の補数」と呼ぶ。
Javaの整数表現を含めコンピューターの多くは、負の整数をこの2の補数で表す。
N進数における「Nの補数」は「対象の数の最大の桁+1桁が1、それ以降の桁が0の数から対象の値を引いた値」を指す。
たとえば10進数の数39の「10の補数」は、100 - 39 = 61となる。
Nの補数は負の意味を持ち、それを利用して足し算で引き算を計算することができる。
たとえば51 - 39 = 12を計算する場合、先ほどの10の補数より51 + 61 = 112、一番上の桁を無視すればこれが答の12と一致していることがわかる。原理については「補数」の項目を参照。
このように補数を利用することで「引き算を足し算で行うことができる」が、10の補数の場合には「補数を作る」「一番上の桁を無視する」際に引き算を利用するため、あまりメリットはない。
ところが2の補数は「ビットを反転し1を足す」だけで作ることができ、「一番上の桁を0にする」こともビット操作で簡単に行えるため、2の補数の作成はコンピューターにとって簡単な処理ということになる。
対して、2進数で「整数の引き算」を行うためには、足し算を行う回路の他に新たに回路を作る必要がある。
そのため、多くのコンピューターは「2の補数を作り足し算をする」ことで、引き算の回路を作らずに済ませている。また、そうなるよう整数のビットを定義している。
2進数の各ビットについて、「0であれば1、1であれば0」に変換したものに、1を足した値を「2の補数」と呼ぶ。
Javaの整数表現を含めコンピューターの多くは、負の整数をこの2の補数で表す。
N進数における「Nの補数」は「対象の数の最大の桁+1桁が1、それ以降の桁が0の数から対象の値を引いた値」を指す。
たとえば10進数の数39の「10の補数」は、100 - 39 = 61となる。
Nの補数は負の意味を持ち、それを利用して足し算で引き算を計算することができる。
たとえば51 - 39 = 12を計算する場合、先ほどの10の補数より51 + 61 = 112、一番上の桁を無視すればこれが答の12と一致していることがわかる。原理については「補数」の項目を参照。
このように補数を利用することで「引き算を足し算で行うことができる」が、10の補数の場合には「補数を作る」「一番上の桁を無視する」際に引き算を利用するため、あまりメリットはない。
ところが2の補数は「ビットを反転し1を足す」だけで作ることができ、「一番上の桁を0にする」こともビット操作で簡単に行えるため、2の補数の作成はコンピューターにとって簡単な処理ということになる。
対して、2進数で「整数の引き算」を行うためには、足し算を行う回路の他に新たに回路を作る必要がある。
そのため、多くのコンピューターは「2の補数を作り足し算をする」ことで、引き算の回路を作らずに済ませている。また、そうなるよう整数のビットを定義している。
参考サイト
- (参考サイトはありません)
// Sample.java
public class Sample
{
public static void main( String[] args )
{
// long型の整数値5を例に見てみます。
long l = 5L;
System.out.println( l );
outputLongBit( l );
// 5
// 0000000000000000000000000000000000000000000000000000000000000101
// ビットを反転します。
l = ~l;
outputLongBit( l );
// 1111111111111111111111111111111111111111111111111111111111111010
// これに1を足せば、2の補数が完成します。
// そして、Javaではこれが「マイナスの値」になります。
l = l + 1;
outputLongBit( l );
System.out.println( l );
// 1111111111111111111111111111111111111111111111111111111111111011
// -5
// -5と比較すると、当然同じです。
long l2 = -5L;
outputLongBit( l2 );
System.out.println( l2 );
// 1111111111111111111111111111111111111111111111111111111111111011
// -5
if( l == l2 )
{
System.out.println( "lとl2は同じ-5です。" );
}
// lとl2は同じ-5です。
}
/**
* 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型の整数値5を例に見てみます。
long l = 5L;
System.out.println( l );
outputLongBit( l );
// 5
// 0000000000000000000000000000000000000000000000000000000000000101
// ビットを反転します。
l = ~l;
outputLongBit( l );
// 1111111111111111111111111111111111111111111111111111111111111010
// これに1を足せば、2の補数が完成します。
// そして、Javaではこれが「マイナスの値」になります。
l = l + 1;
outputLongBit( l );
System.out.println( l );
// 1111111111111111111111111111111111111111111111111111111111111011
// -5
// -5と比較すると、当然同じです。
long l2 = -5L;
outputLongBit( l2 );
System.out.println( l2 );
// 1111111111111111111111111111111111111111111111111111111111111011
// -5
if( l == l2 )
{
System.out.println( "lとl2は同じ-5です。" );
}
// lとl2は同じ-5です。
}
/**
* 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型の整数値5を例に見てみます。 long l = 5L; System.out.println( l ); outputLongBit( l ); // 5 // 0000000000000000000000000000000000000000000000000000000000000101 // ビットを反転します。 l = ~l; outputLongBit( l ); // 1111111111111111111111111111111111111111111111111111111111111010 // これに1を足せば、2の補数が完成します。 // そして、Javaではこれが「マイナスの値」になります。 l = l + 1; outputLongBit( l ); System.out.println( l ); // 1111111111111111111111111111111111111111111111111111111111111011 // -5 // -5と比較すると、当然同じです。 long l2 = -5L; outputLongBit( l2 ); System.out.println( l2 ); // 1111111111111111111111111111111111111111111111111111111111111011 // -5 if( l == l2 ) { System.out.println( "lとl2は同じ-5です。" ); } // lとl2は同じ-5です。 } /** * 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() ); } }