Java中,如果对Integer.MIN_VALUE取反再进行比较,则会得到两个负数。

22
我明天有一场考试,但我无法理解书本上的解释,请帮忙:
public class TestClass{
      public static void main(String[] args) throws Exception{
            int a = Integer.MIN_VALUE;
            int b = -a;
            System.out.println( a+ "   "+b);
      }
}

输出:-2147483648 -2147483648

为什么会打印出两个相同大小的负数而不是正数和负数?

5个回答

41

由于静默整数溢出的原因:Integer.MIN_VALUE-2^31,而Integer.MAX_VALUE2^31-1,所以-Integer.MIN_VALUE等于2^31,即Integer.MAX_VALUE + 1。根据定义,这个值对于一个整数来说太大了,因此会发生溢出并变成Integer.MIN_VALUE...

你也可以验证一下:

System.out.println(Integer.MAX_VALUE + 1);

打印相同的东西。

更具技术性地说,结果由Java语言规范 #15.18.2定义:

如果整数加法溢出,则结果是在某个足够大的二进制补码格式中表示的数学和的低位。如果发生溢出,则结果的符号与两个操作数值的数学和的符号不同。


啊,我的书用二进制给了我一个解释,我更喜欢这个我能更容易理解的解释。非常感谢。 - Quinma
2
另一种实现此问题的方法是使用 Math.abs()Math.abs(Integer.MIN_VALUE) == Integer.MIN_VALUE - martinez314

5
基本上,因为Integer.MAX_VALUE实际上只有2147483647,所以-Integer.MIN_VALUE,它将是+2147483648,实际上超出了整数的内部二进制表示的容量。因此,结果会“循环”,回到Integer.MIN_VALUE,即-2147483648。
如果你使用long b = -((long)a);,那么你会得到预期的结果。

3
为了更加清晰地展示这一点:
Integer.MIN_VALUE is -2^31 = -2147483648
Integer.MAX_VALUE is 2^31-1 = 2147483647 
/*notice this is 1 less than the negative value above*/

Integer.MAX_VALUE无法容纳2147483648。这个数字对于整数来说太大了,超出了1个单位。这会导致数字从最大值返回到起始点,也就是最小值。


0

Java中的整数以32位的二进制补码形式存储。所有二进制补码表示都适用于类似的结果。异常行为是由于额外的负整数引起的,这是二进制补码的一个特殊产物。

-2147483748的带符号位表示为

10000000 00000000 00000000 00000000

而一个数的负数是通过翻转所有位并加一来实现的。最大的正整数将具有按位表示

01111111 11111111 11111111 11111111

这是 2147483647。然后我们再加上一个,所以按位运算,我们有

10000000 00000000 00000000 00000000 == -2147483648

这个额外的整数是二进制补码表示法的一种副作用,对该数字进行操作可能会产生不良后果。-2147483748 确实在整数中是独一无二的!


0

一定数量的二进制位可以编码偶数个事物。这意味着您不能有一个完全以零为中心的序列,因为这将需要对称的事物数。您能够得到的最接近于在句子中间有零的是将其分为负数和非负数,或正数和非正数。正常的二进制补码编码采用前者。因此,32位跨越从-2^31到2^31-1的范围。零位于序列的非负半部分,并且您有一个无法正确取反的负数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接