Java 为什么Integer.MIN_值的绝对值等于Integer.MIN_值

Java 为什么Integer.MIN_值的绝对值等于Integer.MIN_值,java,integer,Java,Integer,在java中,当我说Integer I=Math.abs(Integer.MIN\u VALUE)时。我得到与答案相同的值,这意味着I包含Integer.MIN\u值。 我也在C++中验证了同样的用法。 为什么会有这种行为?请阅读Joshua Bloch的《有效Java》 我找到了这个问题的答案,下面是解释: 计算机使用二进制算术,java中的Math.abs逻辑或任何语言中的absolute函数如下所示: if(num >= 0) return num; else ret

在java中,当我说
Integer I=Math.abs(Integer.MIN\u VALUE)
时。我得到与答案相同的值,这意味着
I
包含
Integer.MIN\u值
。 我也在C++中验证了同样的用法。
为什么会有这种行为?

请阅读Joshua Bloch的《有效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)的2的补码是001(1)
,类似地
110(-2)的2的补码是010(2)
101(-3)的2的补码是011(3)
,而
100(-4)的2的补码是100(-4)
,并且我们可以看到-4是使用3位可能的最小负数


这就是为什么
整数的绝对值。最小值
整数。最小值
这是因为两个补数系统的工作方式<代码>整数。最小值
对应于0x8000000。求反的标准方法是取其1的补码(在本例中为0x7FFFFFFF)并加1,在本例中,它将溢出回0x8000000。

您可能期望
Integer.MIN\u value
的绝对值为
Integer.MAX\u value+1
,但该值超出了原语
int
的大小。而
Integer.MAX\u值+1
又是
Integer.MIN\u值。仅此而已。

这种效应的根本原因是内在的不对称性。32位模式的数量是偶数。其中一个模式用于零。这会留下奇数个非零值。正值和负值的数量不能相等,因为它们的总和是奇数

在用于Java整数的2的补码表示法中,负数的数目比正数的数目大一个。除Integer.MIN_值外的每个负数都对应一个正数,该正数既是其负数也是其绝对值。Integer.MIN_值被保留,没有相应的正int.Math.abs和否定映射到它自身。

Math.abs(int)文档说,如果参数为负,则返回参数的否定。JLS 15.15.4。一元减号运算符表示所有整数值x,-x等于(~x)+1

-Integer.MIN\u VALUE=~Integer.MIN\u VALUE+1=~0x8000000+1=0x7FFFFFFF+1=0x8000000=Integer.MIN\u VALUE

为什么会有这种行为

这是所有现代计算机所使用的表示选择的数学结果

这里有一个非正式的证据来证明为什么必须这样

  • 具有N位的有符号二进制数表示有2N个可能值;i、 元素数为偶数的一组整数

  • 从集合中删除零。集合现在有奇数个元素

  • 现在删除
    {n,-n}
    形式的所有数字对。每次删除一对数字时,集合中仍然包含奇数个元素

  • 现在剩下的一个集合包含奇数个整数,
    n
    在集合中,但
    -n
    不在集合中。由于设置的大小为奇数,因此不能为空;i、 e.至少有一个数字具有此属性

  • 在Java指定的表示中(实际上使用了所有其他实用语言),整数类型有2N-1个负值和2N-1-1个大于零的值。具有奇怪属性的值是
    MIN\u value
    。这种表示称为


    严格来说,整数表示不必有这种异常:

    • 可以有两个零(-0和+0);e、 g.或陈述。(这使证明的第2步无效:现在需要删除2个零。)

    • 可以排除-2N-1;i、 使其成为非法值。(这使证明的步骤1无效:初始集现在有奇数个值。)

    • 可以指定整数算术,以便(例如)对MIN_值求反会引发异常。例如,
      Math.abs(Integer.MIN\u VALUE)
      将引发异常


    然而,所有这些都会对性能产生重大影响,特别是因为现代计算机硬件本身只支持二补运算。他们在编写可靠的整数代码方面也有问题…

    s/compaind/complement/g。java使用两个“S”补码,但C++实现不需要使用两个“S”补码。如果它使用了一个“-补码,上面的内容将不适用。@ChrisJester-Young感谢您建议编辑。s/赞美/补充/g。虽然为时已晚,但它是值得的。为什么要用Integer.MIN_值加1而不是其他整数呢?@dharam这不是一种特殊处理,我试图解释Integer.MIN_值的绝对值大于可以通过int类型重新呈现的最大整数。@dharam In