Javaでは整数はビットレベルで内部的にどのように表されますか?


83

Javaが整数を内部的に格納する方法を理解しようとしています。私はすべてのJavaプリミティブ整数が署名されていることを知っています(短いものを除く?)。つまり、1バイトで使用できるビット数が1つ少なくなります。

私の質問は、すべての整数(正と負)が2の補数として格納されているのか、それとも2の補数の負の数だけなのかということです。

スペックが言っているのがわかりますx bit two's complement number。しかし、私はしばしば混乱します。

例えば:

  int x = 15; // Stored as binary as is?  00000000 00000000 00000000 00001111?
  int y = -22; // Stored as two complemented value? 11111111 11111111 11111111 11101010

編集

明確にするために、 x = 15

   In binary as is: `00000000 00000000 00000000 00001111'
  Two's complement: `11111111 11111111 11111111 11110001`

したがって、答えがall2の補数として格納されている場合は、次のようになります 。

  int x = 15; // 11111111 11111111 11111111 11110001
  int y = -22 // 11111111 11111111 11111111 11101010

ここでも混乱は、記号が言うことです。どちらも負の数です。私はそれを誤解/誤解しているのでしょうか?

編集 私の質問が混乱しているのかわかりません。質問を分離することを余儀なくされました:

私の質問は正確に:正の数はに保存されbinary as is、負の数はとして保存されtwo's complementますか?

すべてが2の補数に格納されると言う人もいれば、負の数だけが2の補数として格納されるという回答もあります。


2の補数は、正の数がその数の実際のビット値で表されることを必然的に意味します...少なくとも私が理解しているように。編集:また、2の補数は、1バイトあたり1ビット少ないビットではなく、プリミティブの合計バイト数の1ビット少ないことを意味します。
LJ2 2012年

あなたの仮定は正しいです:正と負の数は2の補数であり、あなたxyは正しいです。
jlordo 2012年

補足:インターネット時代の言語であるJavaには、たとえばを表すデータ型がないというのは、WTFのようなものです。TCP / IPポート番号(16ビットの符号なしの値)が正確であるため、コードが非常に見苦しい場合があります。
hyde

ウィキの記事en.wikipedia.org/wiki/を確認してください…15に指定した2の補数が間違っています
ダンジョンハンター

@hyde '本当に醜いコード'など?
ローン侯爵2012年

回答:


102

Javaプリミティブデータ型を要約することから始めましょう:

バイト:バイトデータ型は、8ビットの符号付き2の補数整数です。

Short:Shortデータ型は、16ビットの符号付き2の補数整数です。

int: Intデータ型は、32ビットの符号付き2の補数整数です。

long: longデータ型は、64ビットの符号付き2の補数整数です。

float: floatデータ型は、単精度32ビットIEEE754浮動小数点です。

double:doubleデータ型は、倍精度64ビットIEEE754浮動小数点です。

boolean:ブールデータ型は1ビットの情報を表します

char: charデータ型は単一の16ビットUnicode文字です。

ソース

2の補数

「良い例は、256 = 255 + 1であり、(255 − x)がxの1の補数であることに注意することで、2の補数との関係が実現されるというwikiからの例です。

0000 0111 = 72の補数は11111001 = -7です。

それが機能する方法は、MSB(最上位ビット)が負の値を受け取るため、上記の場合

-7 = 1001 = -8 + 0+ 0+ 1

正の整数は通常、単純な2進数として格納されます(1は1、10は2、11は3など)。

負の整数は、絶対値の2の補数として格納されます。正の数の2の補数は、この表記を負の数として使用する場合です。

ソース

この回答でいくつかのポイントを受け取ったので、さらに情報を追加することにしました。

より詳細な答え:

とりわけ、正と負の数を2進数で表すには、次の4つの主要なアプローチがあります。

  1. 署名された大きさ
  2. 1の補数
  3. 2の補数
  4. バイアス

1.署名された大きさ

最上位ビットを使用して符号を表し、残りのビットを使用して絶対値を表します。ここで、0正の数を表し、1負の数を表します。例:

1011 = -3
0011 = +3

この表現はより単純です。ただし、10進数を追加するのと同じ方法で2進数を追加することはできないため、ハードウェアレベルでの実装が難しくなります。さらに、このアプローチでは、2つのバイナリパターンを使用して、0、100 ... 0および0 .... 0を表します。

2.1の補数

この表現では、与えられた数のすべてのビットを反転して、その補数を見つけます。例えば:

010 = 2, so -2 = 101 (inverting all bits).

この表現の問題は、0を表す2つのビットパターン(00..0と11..1)がまだ存在することです。

3.2の補数

数値の負の数を見つけるために、この表現では、すべてのビットを反転してから1ビットを追加します。1ビットを追加すると、0を表す2つのビットパターンを持つ問題が解決されます。この表現では、1つ(00 ... 0)しかありません。

たとえば、4ビットを使用して4(10進数)の2進数の負の表現を見つけたいとします。まず、4をバイナリに変換します。

4 = 0100

次に、すべてのビットを反転します

0100 -> 1011

最後に、1ビット追加します

1011 + 1 = 1100.

したがって、4ビットの2の補数のバイナリ表現を使用している場合、1100は10進数で-4に相当します。

補数を見つけるより速い方法は、値1として最初のビットを固定し、残りのビットを反転することです。上記の例では、次のようになります。

0100 -> 1100
^^ 
||-(fixing this value)
|--(inverting this one)

2の補数表現は、0の表現が1つしかないことに加えて、10進数と同じ方法で2つのバイナリ値を追加し、符号が異なる偶数を追加します。それでも、オーバーフローのケースをチェックする必要があります。

4.バイアス

この表現は、浮動小数点のIEEE754標準の指数を表すために使用されます。すべてのビットがゼロのバイナリ値が最小値を表すという利点があります。また、すべてのビットが1のバイナリ値が最大値を表します。名前が示すように、値はバイアス(通常は2 ^(n-1)または2 ^(n-1)-1)のnビットでバイナリにエンコード(正または負)されます。

したがって、8ビットを使用している場合、10進数の値1は、2 ^(n-1)のバイアスを使用して2進数で表されます。

+1 + bias = +1 + 2^(8-1) = 1 + 128 = 129
converting to binary
1000 0001

2
私の質問は正確に:+ veのbinary as is数はに保存されtwo's complementますが、-veの数はに保存されますか?
ケビン・レイヴ

1
通常、正の整数は単純な2進数として格納され、負の整数は2の補数として格納されます。
dreamcrash 2012年

それが私の質問に答えます。ソースはありますか?これを明確に述べている文書は見つかりませんでした。
ケビン・レイヴ

ecomware.comからの上記のリンクは@dreamcrashで壊れていますが、他に何か提供できますか?
ラムパトラ2014年

@Ramswaroopこんにちは、この1つはどう
ですか

61

Java整数は32ビットであり、常に符号付きです。これは、最上位ビット(MSB)が符号ビットとして機能することを意味します。anintで表される整数は、ビットの加重和に他なりません。重みは次のように割り当てられます。

Bit#    Weight
31      -2^31
30       2^30
29       2^29
...      ...
2        2^2
1        2^1
0        2^0

MSBの重みは負(実際には可能な最大の負)であるため、このビットがオンの場合、整数(加重和)は負になることに注意してください。

4ビットの数値でシミュレートしてみましょう。

Binary    Weighted sum            Integer value
0000       0 + 0 + 0 + 0           0
0001       0 + 0 + 0 + 2^0         1
0010       0 + 0 + 2^1 + 0         2
0011       0 + 0 + 2^1 + 2^0       3
0100       0 + 2^2 + 0 + 0         4
0101       0 + 2^2 + 0 + 2^0       5
0110       0 + 2^2 + 2^1 + 0       6
0111       0 + 2^2 + 2^1 + 2^0     7 -> the most positive value
1000      -2^3 + 0 + 0 + 0        -8 -> the most negative value
1001      -2^3 + 0 + 0 + 2^0      -7
1010      -2^3 + 0 + 2^1 + 0      -6
1011      -2^3 + 0 + 2^1 + 2^0    -5
1100      -2^3 + 2^2 + 0 + 0      -4
1101      -2^3 + 2^2 + 0 + 2^0    -3
1110      -2^3 + 2^2 + 2^1 + 0    -2
1111      -2^3 + 2^2 + 2^1 + 2^0  -1

したがって、2の補数は負の整数を表すための排他的なスキームではなく、整数の2進表現は常に同じであり、最上位ビットの重みを否定するだけであると言えます。そして、そのビットが整数の符号を決定します。

Cには、unsigned宣言に使用できるキーワード(Javaでは使用できません)がありますunsigned int x;。符号なし整数では、MSBの重みは2^31負ではなく正()です。その場合、の範囲unsigned int02^32 - 1であり、のint範囲-2^312^31 - 1。です。

別の観点からは、の2の補数を検討している場合xとして~x + 1(NOT Xプラス1)、ここでの説明ですが:

いずれかのためにx~xのちょうどビット単位の逆数であるxどこので、x持っている1ビットを、~x持っています0がビット(およびその逆を)。したがって、これらを合計すると、加算にキャリーはなく、合計はすべてのビットがである整数になります1

32ビット整数の場合:

x + ~x = 1111 1111 1111 1111 1111 1111 1111 1111
x + ~x + 1 =   1111 1111 1111 1111 1111 1111 1111 1111 + 1
           = 1 0000 0000 0000 0000 0000 0000 0000 0000

左端の1ビットは32ビットに収まらないため(整数オーバーフロー)、単に破棄されます。そう、

x + ~x + 1 = 0
-x = ~x + 1

したがって、ネガティブxは、で表すことができることがわかります~x + 1。これは、の2の補数と呼ばれますx


私の質問は正確に:+ veのbinary as is数はに保存されtwo's complementますが、-veの数はに保存されますか?
ケビン・レイヴ

はい、そうです。負の数は、その正の値の2の補数としてコンピューターに表されます。
0605002 2012年

4
素晴らしい答えと説明Bonny @ 0605002、+ 1 :)
KM Rakibul Islam 2012

@ 0605002:もしあれば、この回答への参照を教えていただけますか?私はその概念を知っていましたが、実際にはそのように考えたことはありませんでした。最も単純でありながら正確な答え。
AbhishekSingh18年

大学の4年間、私は2の補数を理解していませんでした。この答えは私にもっと教えてくれました。そのような単純なことが世界中でそのような不可解な方法で教えられるのはとても悲しいことです。
Prashant Pandey 2018

10

私はそれを知るために次のプログラムを実行しました

public class Negative {
    public static void main(String[] args) {
        int i =10;
        int j = -10;

        System.out.println(Integer.toBinaryString(i));
        System.out.println(Integer.toBinaryString(j));
    }
}

出力は

1010
11111111111111111111111111110110

出力から、2の補数を使用しているようです。


1
10の2の補数はです11111111 11111111 11111111 11110110。10の2進数が1010である間、あなたは印刷します。それで、-veの数だけが2の補数として保存されますか?
ケビン・レイヴ

ウィキの記事en.wikipedia.org/wiki/を確認してください…15に指定した2の補数が間違っています
ダンジョンハンター

msbビットが1で始まる場合、負の数になります
Dungeon Hunter

はい2の補数は10です111111111111111 11111111111110110これは-10です
ダンジョンハンター

+ veの数値は、2の補数に符号ビットを残して2進数として格納されます
Dungeon Hunter

4

Oracleは、興味深いと思われるJavaデータ型に関するいくつかのドキュメントを提供しています。具体的には:

int:intデータ型は、32ビットの符号付き2の補数整数です。最小値は-2,147,483,648、最大値は2,147,483,647(両端を含む)です。

ところで、shortも2の補数として格納されます。


3

このドキュメントによると、すべての整数は署名され、Javaの2の補数形式で格納されます。その信頼性は定かではありません。


「2の補数形式では、正の値は単純な2進数として表されます。」同じ文書に書かれているので、技術的には正しいです。:)
Shashi 2013

3

正の数はそのまま保存/取得されます。

e.g) For +ve number 10; byte representation will be like 0-000 0010 
                                               (0 - MSB will represent that it is +ve).
So while retrieving based on MSB; it says it is +ve, 
so the value will be taken as it is. 

ただし、負の数は2の補数(MSBビット以外)の後に格納され、MSBビットは1に設定されます。

例)-10を保存する場合

  0-000 0010  -> (1's complement) -> 0-111 1101 
              -> (2's complement) 0-111 1101 + 1 -> 0-111 1110
  Now MSB will be set to one, since it is negative no -> 1-111 1110

取得時に、MSBが1に設定されていることがわかりました。したがって、負の数ではありません。また、2の補数はMSB以外で実行されます。

  1-111 1110  --> 1-000 0001 + 1 --> 1-000 0010
  Since MSB representing this is negative 10 --> hence  -10 will be retrived.

鋳造

また、int / shortをbyteにキャストする場合、最後のバイトのMSBとともに最後のバイトのみが考慮されることに注意してください。

「-130」の例を短くすると、次のように保存される可能性があります

(MSB)1-(2's complement of)130(1000 0010) --> 1-111 1111 0111 1110

ここで、バイトキャストは0111 1110である最後のバイトを取得しました。(0-MSB)MSBは+ ve値であると言っているので、そのまま取得されます。これは126です。(+ ve)。

別の例「130」を短くすると、次のように保存される可能性があります

  0-000 000 1000 0010     (MSB = 0)

これで、バイトキャストは最後のバイトである10000010を取得しました。(1 = MSB)MSBは-ve値であると言っているので、2の補数が実行され、負の数が返されます。したがって、この場合、-126が返されます。

 1-000 0010  -> (1's complement) -> 1-111 1101 
             -> (2's complement) 1-111 1101 + 1 -> 1-111 1110 -> (-)111 1110
               = -126

(int)(char)(byte)-1と(int)(short)(byte)-1の差

(byte)-1       -> 0-000 0001 (2's Comp) -> 0-111 1111 (add sign) -> 1-111 1111
(char)(byte)-1 -> 1-111 1111 1111 1111  (sign bit is carry forwarded on left) 

同様に

(short)(byte)-1-> 1-111 1111 1111 1111  (sign bit is carry forwarded on left) 

だが

(int)(char)(byte)-1 -> 0-0000000 00000000 11111111 11111111  = 65535
since char is unsigned; MSB won't be carry forwarded. 

そして

(int)(Short)(byte)-1 -> 1-1111111 11111111 11111111 11111111 = -1
since short is signed; MSB is be carry forwarded. 

参考文献

負の数を表すために2の補数が使用されるのはなぜですか?

「2の補数」とは何ですか?



2

最上位ビット(32番目)は、数値が正または負であることを示します。0の場合、数値が正であり、実際のバイナリ表現で格納されていることを意味します。ただし、1の場合は、数値が負であり、2の補数表現で格納されていることを意味します。したがって、バイナリ表現から整数値を復元しながら、32番目のビットに重み-2 ^ 32を与えると、実際の答えが得られます。


1
StackOverflowへようこそ!:D
0605002 2012年

2

答えてくれてありがとう、dreamcrash https://stackoverflow.com/a/13422442/1065835 ; 上のwikiページ、彼らは私が正の数の負のカウンターパートのバイナリ表現を見つける方法を理解助けた例を与えます。

たとえば、1バイト(= 2ニブル= 8ビット)を使用すると、10進数の5は次のように表されます。

0000 01012最上位ビットは0であるため、パターンは非負の値を表します。2の補数表記で-5に変換するには、ビットを反転します。0は1になり、1は0になります。

1111 1010この時点で、数値は10進値-5の1の補数です。2の補数を取得するには、結果に1を加算して、次のようにします。

1111 1011結果は、2の補数形式で10進値-5を表す符号付き2進数です。最上位ビットは1であるため、表される値は負です。


1

正の数は2進数として直接格納されます。負の数には2の補数が必要です。

例えば:

15:00000000 00000000 00000000 00001111
-15:11111111 11111111 11111111 11110001

これが符号付きビットの違いです。


1

正の整数の場合、2の補数の値はMSBビット0と同じ(like +14 2'complement is 01110)です。

負の整数のみについて、2 '補数を計算しています(-14= 10001+1 = 10010)

したがって、最終的な答えは、両方の値(+ve and -ve)が2の補数形式でのみ格納されるということです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.