在java中我说Integer i = Math.abs(Integer.MIN_VALUE)
。我得到与答案相同的值,这意味着i
包含Integer.MIN_VALUE
。
我在C ++中也验证了相同的内容。
为什么会出现这种情况?
答案 0 :(得分:12)
在Joshua Bloch的Effective Java中阅读。
我找到了这个问题的答案,这里是解释:
计算机使用二进制算术,java中的Math.abs
逻辑或任何语言的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位,那么这里是可以使用四位产生的数字列表:
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) is 001(1)
的2的补码,110(-2) is 010(2)
的2的补码,101(-3) is 011(3)
的2的补码和100(-4) is 100(-4)
的2的补码可以看出-4是使用3位可能的最小负数。
这就是Integer.MIN_VALUE
的绝对值为Integer.MIN_VALUE
的原因。
答案 1 :(得分:5)
存在固有的不对称性,这是造成这种影响的根本原因。 32位位模式的数量是偶数。其中一种模式用于零。这留下了奇数个非零值。正值的数量和负值的数量不能相等,因为它们的总和是奇数。
在用于Java整数的2的补码表示中,负数的数量比正数的数量大1。除Integer.MIN_VALUE之外的每个负数对应于正数,该正数既是其否定值,也是其绝对值。 Integer.MIN_VALUE保留,没有相应的正int。 Math.abs和否定将它映射到自身。
答案 2 :(得分:4)
为什么会这样?
这是所有现代计算机中使用的表示选择的数学结果。
这是一个非正式的证明,为什么 就是这样。
带有N位的带符号二进制数表示具有2个 N 可能的值;即具有偶数元素的集合整数。
从集合中删除零。该集合现在具有奇数个元素。
现在删除{n, -n}
形式的所有对。每次我们删除一对数字时, 集都包含奇数个元素。
我们现在留下一个包含奇数个整数的集合,n
在集合中,但-n
不在集合中。由于设定的大小是奇数,因此不能为空;即具有此属性的至少一个号码。
在Java指定的表示中(实际上使用了所有其他实用语言),整数类型具有2个 N-1 负值和2个 N-1 - 1个值大于零。具有奇怪属性的值为MIN_VALUE
。此表示称为two's complement。
严格地说,整数表示不必具有此异常:
可以有两个零(-0和+0);例如signed magnitude或one's complement表示。 (这使证明的第2步无效:现在有2个零要删除。)
可以排除-2 N-1 ;即使其成为非法价值。 (这使证明的第1步无效:初始集现在具有奇数个值。)
可以指定整数运算,以便(例如)否定MIN_VALUE引发异常。例如,Math.abs(Integer.MIN_VALUE)
会抛出异常。
然而,所有这些都具有重要的性能影响,特别是因为现代计算机硬件本身仅支持二进制补码算法。它们在编写可靠的整数代码方面也存在问题......
答案 3 :(得分:3)
Math.abs(int)docs说如果参数为负数,则返回参数的否定。 JLS 15.15.4。一元减运算符表示对于所有整数值x,-x等于(~x)+1 。
-Integer.MIN_VALUE = ~Integer.MIN_VALUE + 1 = ~0x80000000 + 1 = 0x7FFFFFFF + 1 = 0x80000000 = Integer.MIN_VALUE
答案 4 :(得分:2)
您可能希望Integer.MIN_VALUE
的绝对值为Integer.MAX_VALUE + 1
,但此值超出原始int
大小。而Integer.MAX_VALUE + 1
又是Integer.MIN_VALUE
。就是这样。
答案 5 :(得分:1)
这是因为二进制数系统的工作方式。 Integer.MIN_VALUE
对应于0x80000000。否定它的标准方法是取其补码(在这种情况下为0x7FFFFFFF)并加1,在这种情况下它会溢出回0x80000000。