なぜ整数。MAX_VALUE+1==整数です。MIN_VALUE?
-
29-10-2019 - |
質問
System.out.println(Integer.MAX_VALUE + 1 == Integer.MIN_VALUE);
真である。
私はJavaの整数が32ビットであり、2を超えることはできないことを理解しています31-1、しかし、なぜ1をそのに追加するのか理解できません MAX_VALUE
結果は次のとおりです。 MIN_VALUE
そして、ある種の例外ではありません。Rubyのように、より大きな型への透過的な変換のようなものは言及していません。
この動作はどこかで指定されていますか?私はそれに頼ることができますか?
解決
整数がオーバーフローするためです。オーバーフローすると、次の値は次のようになります Integer.MIN_VALUE
. 関連するJLS
整数の加算がオーバーフローした場合、結果は、十分に大きな2の補数形式で表される数学的和の下位ビットになります。オーバーフローが発生した場合、結果の符号は、2つのオペランド値の数学的合計の符号と同じではありません。
他のヒント
整数ストレージがオーバーフローされ、 JSL3rd Edに記載されているように、それは決して示されていません。:
組み込みの整数演算子は、オーバーフローやアンダーフローを示すものではありません。整数演算子はaを投げることができます
NullPointerException
変換を開梱する場合 (§5.1.8) null参照の必要があります。それ以外は、例外をスローできる唯一の整数演算子です (§11) は整数除算演算子です/
(§15.17.2) および整数剰余演算子%
(§15.17.3), 、投げるかどれがArithmeticException
右側のオペランドがゼロで、インクリメント演算子とデクリメント演算子がある場合++
(§15.15.1, §15.15.2)と--
(§15.14.3, §15.14.2)、投げることができるOutOfMemoryError
ボクシング変換の場合 (§5.1.7) 必要であり、変換を実行するのに十分なメモリがありません。
4ビットストレージの例:
MAX_INT: 0111 (7)
MIN_INT: 1000 (-8)
MAX_INT+1:
0111+
0001
----
1000
整数値がバイナリ形式でどのように表現されるか、およびバイナリ加算がどのように機能するかを理解する必要があります。Javaでは、2の補数と呼ばれる表現を使用し、数値の最初のビットがその符号を表します。ビット符号が0の最大のjava整数に1を追加するたびに、そのビット符号は1になり、数値は負になります。
このリンクでは、詳細について説明します: http://www.cs.grinnell.edu/~/~/~/~/~/~/~/~/~/~/~/~/~/~/~/~/~/~/~/~/
--
Java言語仕様では、この動作をここで扱います: http://docs.oracle.com/javase/specs/jls/se6/html/expressions.html#15.18.2
整数の加算がオーバーフローした場合、結果は、十分に大きな2の補数形式で表される数学的和の下位ビットになります。オーバーフローが発生した場合、結果の符号は、2つのオペランド値の数学的合計の符号と同じではありません。
これは、この動作に頼ることができることを意味します。
ほとんどのプロセッサでは、算術命令にはオーバーフローでフォールトするモードがありません。彼らはチェックする必要があるフラグを設定します。それは余分な命令なので、おそらく遅くなります。言語の実装を可能な限り高速にするために、エラーを無視して続行するように言語が指定されることがよくあります。Javaの場合、動作は次のように指定されます JLS.Cの場合、言語は動作を指定していませんが、最新のプロセッサはJavaとして動作します。
私は、符号なしの操作だけでなく、オーバーフローをスローする(厄介な)Java SE8ライブラリの提案があると信じています。私はDSPの世界で人気があると信じている行動は、最大値で値をクランプしているので、 Integer.MAX_VALUE + 1 == Integer.MAX_VALUE
[Javaではありません]。
私は将来の言語が任意の精度intを使用すると確信していますが、まだしばらくの間はそうではありません。迅速に実行するには、より高価なコンパイラ設計が必要です。
国際日付変更線を越えたときに日付が変更されるのと同じ理由:そこには不連続性があります。これは、バイナリ加算の性質に組み込まれています。
これは、整数が次のように表されるという事実に関連するよく知られた問題です 二の補数 バイナリ層の下にあります。2の補数の最大値に1を追加すると、最小値が得られます。正直なところ、すべての整数はjavaが存在する前にこのように動作し、Java言語のこの動作を変更すると、整数演算にオーバーヘッドが追加され、他の言語から
あなたが追加するとき 3
(バイナリで 11
)から1(バイナリで 1
)、に変更する必要があります 0
(バイナリで 0
)すべてのバイナリ 1
右から始めて、0になるまで、これを変更する必要があります 1
. Integer.MAX_VALUE
すべての場所がいっぱいになっています 1
だからそこに残っているだけです 0
s.
原因オーバーフローと2準拠の自然数は"2番目のループ"になり、最も右の位置2147483647にあり、1を合計した後、最も左の位置-2147483648に表示され、次のインクリメントは-2147483647、-2147483646、-2147483645、になります。..そして、このビット深度でのマシンの加算の性質は、何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も何度も繰り返します。
いくつかの例:
int a = 2147483647;
System.out.println(a);
与える:2147483647
System.out.println(a+1);
与える:-2147483648(オーバーフローと2準拠の自然数が"2番目のループ"になり、最も右の位置2147483647にあり、1を合計した後、最も左の位置-2147483648に表示され、次のインクリメントは-2147483648、-2147483647、-2147483646、になります。..そして、このビット深度の加算機の性質は、再び最も右に前方に、そして上に、その性質)
System.out.println(2-a);
与える:-2147483645(-2147483647+2は数学的論理的と思われる)
System.out.println(-2-a);
与える:2147483647 (-2147483647-1 -> -2147483648, -2147483648-1 -> 2147483647 前の回答で説明されているいくつかのループ)
System.out.println(2*a);
与える:-2 (2147483647+2147483647 -> -2147483648+2147483646 再び数学的論理)
System.out.println(4*a);
与える:-4 (2147483647+2147483647+2147483647+2147483647 -> -2147483648+2147483646+2147483647+2147483647 -> -2-2 (最後の答えによると)->-4)`