为什么Integer.MAX_VALUE + 1 == Integer.MIN_VALUE?

时间:2012-02-22 15:14:14

标签: java integer integer-overflow twos-complement jls

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

是真的。

我知道Java中的整数是32位且不能超过2 31 -1,但我无法理解为什么在MAX_VALUE中添加1导致{{ 1}}而不是某种例外。没有提到透明转换为更大类型的东西,比如Ruby。

是否在某处指定了此行为?我能依靠吗?

9 个答案:

答案 0 :(得分:28)

因为整数溢出。当它溢出时,下一个值为Integer.MIN_VALUERelevant JLS

  

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

答案 1 :(得分:24)

整数存储空间溢出且that is not indicated in any way, as stated in JSL 3rd Ed.

  

内置整数运算符不以任何方式指示溢出或下溢。如果需要空引用的转箱(§5.1.8),则整数运算符可以抛出NullPointerException。除此之外,唯一可以抛出异常(§11)的整数运算符是整数除运算符/ (§15.17.2)和整数余数运算符% (§15.17.3),其中如果右侧操作数为零,则抛出ArithmeticException;增量和减量运算符++§15.15.1§15.15.2)和--({{3 }},§15.14.3),如果需要装箱转换§15.14.2并且没有足够的内存可用于执行转换,则可以抛出OutOfMemoryError

4位存储中的示例:

MAX_INT: 0111 (7)
MIN_INT: 1000 (-8)

MAX_INT + 1:

 0111+
 0001
 ----
 1000

答案 2 :(得分:8)

您必须了解整数值如何以二进制形式表示,以及二进制加法的工作原理。 Java使用称为二进制补码的表示,其中数字的第一位表示其符号。每当你向最大的java Integer(其位符号为0)加1时,它的位符号变为1,数字变为负数。

此链接详细说明了http://www.cs.grinnell.edu/~rebelsky/Espresso/Readings/binary.html#integers-in-java

-

Java语言规范在此处理此行为:http://docs.oracle.com/javase/specs/jls/se6/html/expressions.html#15.18.2

  

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

这意味着您可以依赖此行为。

答案 3 :(得分:7)

在大多数处理器上,算术指令无溢出故障模式。他们设置了一个必须检查的标志。这是一个额外的指令,所以可能更慢。为了使语言实现尽可能快,通常会指定语言来忽略错误并继续。对于Java,行为在JLS中指定。对于C,语言不指定行为,但现代处理器将表现为Java。

我相信有些(笨拙的)Java SE 8库提出了溢出和无符号操作的建议。我相信在DSP领域很受欢迎的行为是将值限制在最大值,因此Integer.MAX_VALUE + 1 == Integer.MAX_VALUE [不是Java]。

我确信未来的语言将使用任意精度的int,但暂时还没有。需要更昂贵的编译器设计才能快速运行。

答案 4 :(得分:4)

当您跨越国际日期行时日期发生变化的原因相同:那里存在不连续性。它内置于二元加法的本质中。

答案 5 :(得分:4)

这是一个众所周知的问题,即整数在二进制层表示为two's complement。当您将2的补码数的最大值加1时,您将获得最小值。老实说,所有整数在java存在之前都是这样的,并且改变Java语言的这种行为会给整数数学带来更多的开销,并且混淆了来自其他语言的程序员。

答案 6 :(得分:3)

3(二进制11)添加到1(二进制1)时,您必须更改为0(二进制0)所有二进制1从右边开始,直到你得到0,你应该更改为1Integer.MAX_VALUE所有地方都填充了1,因此仅保留0个。

答案 7 :(得分:0)

通过字节示例易于理解=> enter image description here

byte a=127;//max value for byte
byte b=1;

byte c=(byte) (a+b);//assigns -128
System.out.println(c);//prints -128

这里我们强制加法并将其转换为字节。 那么将会发生的情况是,当我们达到 127(一个字节的最大可能值)并加上 1 时,该值从 127 翻转(如图所示)并变为 -128。 值开始在类型周围盘旋。

整数也是如此。

还有 integer + integer 保持整数(不像 byte + byte 被转换为 int [除非像上面那样强制转换])。

int int1=Integer.MAX_VALUE+1;
System.out.println(int1); //prints -2147483648
System.out.println(Integer.MIN_VALUE); //prints -2147483648

//below prints 128 as converted to int as not forced with casting
System.out.println(Byte.MAX_VALUE+1);

答案 8 :(得分:-1)

导致溢出,并且两个兼容的自然计数在“第二个循环”上进行,我们位于最右边的位置2147483647,求和1之后,我们出现在最左边的位置-2147483648,接下来的增量是-2147483647,-2147483646, -2147483645,...如此反复,直到最右边,在此位深度上求和器的性质。

一些例子:

int a = 2147483647;

System.out.println(a);

给出:2147483647

System.out.println(a+1);

给出:-2147483648(由于溢出和两个兼容的自然计数在“第二循环”中进行,我们位于最右边的位置2147483647,求和1之后,我们出现在最左边的位置-2147483648,下一次增加是- 2147483648,-2147483647,-2147483646 ...等等,然后又一次又一次地前进到最右端,在这个位深度上求和器的性质)

System.out.println(2-a); 

gives:-2147483645(-2147483647 + 2似乎是数学逻辑)

System.out.println(-2-a);

给出:2147483647(-2147483647-1-> -2147483648,-2147483648-1-> 2147483647前面的答案中描述的某些循环)

System.out.println(2*a);

给出:-2(2147483647 + 2147483647-> -2147483648 + 2147483646再次是数学逻辑)

System.out.println(4*a);

给出:-4(2147483647 + 2147483647 + 2147483647 + 2147483647-> -2147483648 + 2147483646 + 2147483647 + 2147483647-> -2-2(根据最后一个答案)-> -4)`