在 java 中当我说Integer i = Math.abs(Integer.MIN_VALUE)
. 我得到与答案相同的值,这意味着i
包含Integer.MIN_VALUE
。我也在 C++ 中验证了相同的内容。
为什么会有这种行为?
在 Joshua Bloch 的 Effective Java 中阅读此内容。
我找到了这个问题的答案,这里是解释:计算机使用二进制算术,Math.abs
java 中的逻辑或absolute
任何语言的函数如下所示:
if(num >= 0)
return num;
else
return (2's complement of the num);
注意:如何找到 2 的补码
对于给定的数字,我们首先找到它的 1 的补码,然后将其加 1。例如,考虑我们的数字是10101
1 的补码 = 01010
2 的补码 = 01011
(将 1 添加到 1 的补码)
现在,为了简单明了,让我们说我们的整数(有符号)大小是 3 位,那么这里是可以使用 4 位产生的可能的数字列表:
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`
从上面的演示中,我们发现 的 2 的补码111(-1) is 001(1)
,类似地 的 2 的补码110(-2) is 010(2)
, 的 2 的补码101(-3) is 011(3)
和 的 2 的补码,100(-4) is 100(-4)
我们可以看到 -4 是使用 3 位可能的最小负数。
Integer.MIN_VALUE
这就是 absolute of is的原因Integer.MIN_VALUE
。
存在一种固有的不对称性,这是这种效应的根本原因。32 位位模式的数量是偶数。其中一种模式用于零。这留下了奇数个非零值。正值的数量和负值的数量不能相等,因为它们的和是奇数。
在用于 Java 整数的 2 的补码表示中,负数的数量比正数的数量大一。除 Integer.MIN_VALUE 之外的每个负数都对应一个正数,该正数既是它的负数,也是它的绝对值。剩下的 Integer.MIN_VALUE,没有对应的正整数。Math.abs 和否定将其映射到自身。
为什么会有这种行为?
这是所有现代计算机中使用的表示选择的数学结果。
这是一个非正式的证明,说明为什么必须这样。
一个有 N 位的有符号二进制数表示有 2 N个可能的值;即具有偶数个元素的集合整数。
从集合中删除零。该集合现在具有奇数个元素。
现在删除表格中的所有数字对{n, -n}
。每次我们删除一对数字时,集合仍然包含奇数个元素。
我们现在剩下一个集合,其中包含奇数个整数,它n
在集合中,但-n
不在集合中。由于集合大小是奇数,所以不能为空;即这个属性至少有一个数字。
在 Java 指定的表示形式中(并且实际上使用了所有其他实用语言),整数类型有 2 N-1 个负值和 2 N-1 - 1 个大于零的值。具有奇怪属性的值是MIN_VALUE
。这种表示称为二进制补码。
严格来说,整数表示不一定有这个异常:
可以有两个零(-0 和 +0);例如有符号的幅度或一个的补码表示。(这使证明的第 2 步无效:现在有 2 个零要删除。)
可以排除 -2 N-1;即使其成为非法值。(这使证明的第 1 步无效:初始集合现在具有奇数个值。)
可以指定整数算术,以便(例如)否定 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
对应于 0x80000000。否定它的标准方法是取其补码(在这种情况下为 0x7FFFFFFF)并加 1,在这种情况下它将溢出回 0x80000000。