为什么2147483647 + 1实际上是-2147483648?

时间:2018-01-09 02:15:11

标签: java overflow

在我的java教科书中,它显示为“2147483647 + 1实际上是-2147483648”

我理解这是因为溢出,但为什么他们选择让它等于最小整数值?

1 个答案:

答案 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,这样就不需要特殊的硬件来容纳它,并且计数行为是连续的零。这有两个后果

  1. 最左边的位告诉我们数字是正数(0)还是负数(1)
  2. 由于零点没有不连续性,您可以添加负数和正数,并获得正确的结果,无需任何特殊考虑。算术运算添加二进制+1和-1,你就得零。
  3. 现在让我们看一下事情的另一端。继续减去,直到你到达:

        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)代表负数。