在Java中,当我使用
为什么会出现这种行为?
Integer i = Math.abs(Integer.MIN_VALUE)
时,我得到的答案与原始值相同,这意味着i包含了Integer.MIN_VALUE
。我在C++中进行过验证。为什么会出现这种行为?
请阅读 Joshua Bloch 的《Effective Java》。
我找到了这个问题的答案,以下是解释:
计算机使用二进制算术,Java 中的 Math.abs
函数或任何语言中的 absolute
函数的逻辑如下:
if(num >= 0)
return num;
else
return (2's complement of the num);
注意:如何找到二进制补码
对于给定的数字,我们首先找到它的一补数,然后再加1。例如:
假设我们的数字为10101
,
则其一补数为01010
,
二补数为01011
(在一补数上加1)。
现在,为了方便和清晰起见,假设我们的整数(有符号)大小为3位,下面是可以使用这四个位生成的可能数字列表:
000 --> 0 (0)
001 --> 1 (1)
010 --> 2 (2)
011 --> 3 (3)
100 --> 4 (-4)
101 --> 5 (-3)
110 --> 6 (-2)
111 --> 7 (-1)
现在这个被签署了,这意味着一半的数字是负数,而另一半是正数(以第一位为1的数字是负数)。让我们从000
开始寻找它的负数,它将是000
的二进制补码。2's complement of `000` = 1 + `111` = `000`
2's complement of `001` = 1 + `110` = `111`
2's complement of `010` = 1 + `101` = `110`
2's complement of `011` = 1 + `100` = `101`
2's complement of `100` = 1 + `011` = `100`
2's complement of `101` = 1 + `010` = `011`
2's complement of `110` = 1 + `001` = `010`
2's complement of `111` = 1 + `000` = `001`
从上面的演示中,我们发现111(-1)的2补码是001(1)
,同样110(-2)的2补码是010(2)
,101(-3)的2补码是011(3)
,100(-4)的2补码是100(-4)
,我们可以看到,-4是使用3位表示的最小负数。Integer.MIN_VALUE
的绝对值是Integer.MIN_VALUE
的原因。MIN_VALUE
。这种表示称为二进制补码。
Math.abs(Integer.MIN_VALUE)
将抛出异常。Math.abs(int)文档说:如果参数为负数,则返回参数的相反数。 JLS 15.15.4. 负一元运算符说:对于所有整数值x,-x等于(~x)+1。
-Integer.MIN_VALUE = ~Integer.MIN_VALUE + 1 = ~0x80000000 + 1 = 0x7FFFFFFF + 1 = 0x80000000 = Integer.MIN_VALUE
您可能期望Integer.MIN_VALUE
的绝对值为Integer.MAX_VALUE + 1
,但是这个值已经超出了原始的int
大小。而Integer.MAX_VALUE + 1
又会变成Integer.MIN_VALUE
。就是这样。
Integer.MIN_VALUE
和Integer.MAX_VALUE
刚好是彼此的补码。 - C. K. YoungInteger.MIN_VALUE
和 Integer.MAX_VALUE
并不真正互补(除非你只是说它们是最小值和最大值)。由于在二进制补码形式中,负数比正数多表示一个,所以 Integer.MIN_VALUE
的 幅度 比 Integer.MAX_VALUE
大一。 - DaoWenInteger.MIN_VALUE
和 Integer.MAX_VALUE
是彼此的补码。 - C. K. YoungInteger.MIN_VALUE
对应着 0x80000000。将其取反(在此情况下为 0x7FFFFFFF),再加上1,是标准的求相反数的方法。但在这种情况下,会发生溢出,导致结果回到了 0x80000000。