在我的java教科书中,它显示为“2147483647 + 1实际上是-2147483648”
我理解这是因为溢出,但为什么他们选择让它等于最小整数值?
答案 0 :(得分:6)
没有人“选择”溢出以这种方式工作,这是两个补码表示中加法的自然结果。 32位数字可以表示4,294,967,296个不同的值。无符号数(Java没有)的范围为[0..4,294,967,295]。
两个补码分割整个范围,使得其中一半表示数字> = 0而另一半表示数字< 0,它以易于在硬件中实现的方式执行此操作。
让我们用二进制数来计算
Decimal Binary
----------- -----------------------------------
2 00000000 00000000 00000000 00000010
1 00000000 00000000 00000000 00000001
0 00000000 00000000 00000000 00000000
-1 11111111 11111111 11111111 11111111
-2 11111111 11111111 11111111 11111110
如果您将二进制数视为汽车里程表,可能会有所帮助。不同之处在于此计数器可以向任一方向移动。因此,当向下计数时,当它变为零时,它会回绕到最大的无符号正数。两个补码的作用是调用该位模式(全1)-1
,这样就不需要特殊的硬件来容纳它,并且计数行为是连续的零。这有两个后果
现在让我们看一下事情的另一端。继续减去,直到你到达:
Decimal Binary
----------- -----------------------------------
-2147483647 10000000 00000000 00000000 00000001
-2147483648 10000000 00000000 00000000 00000000
now, if you subtract 1 more...
? 01111111 11111111 11111111 11111111
但结果位模式只是可以表示的最大正数字,或2147483647.将1加回到此值并绕回最小的负数。
-2147483648 10000000 00000000 00000000 00000000
两个补语有两种选择。一个补码和“符号幅度”,两者都需要更复杂的硬件来进行算术运算,因为它们表现出零的不连续性。两者都有+0和-0具有不同的表示,在进行算术时需要进行调整。
如果你使用带有十进制的二进制补码做同样的事情,它将被称为“数十补码”并且会像这样工作(为简单起见,我将使用一个3位数的计数器)
Actual 10's complement
Value representation
------ ---------------
499 499
2 002
1 001
0 000
-1 999
-2 998
-499 501
-500 500
以与2的补码相同的方式,我们采用0-999(1000个值)的无符号范围并将其拆分,使得一半(0-499)代表零,正值和另一半( 500-999)代表负数。