34

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

是真的。

我知道Java中的整数是32位的,不能超过2 31 -1,但我不明白为什么在它的MAX_VALUE结果中加1MIN_VALUE而不是在某种异常中。更不用说像 Ruby 那样将透明转换为更大的类型。

这种行为是否在某处指定?我可以依靠它吗?

4

9 回答 9

34

因为整数溢出。当它溢出时,下一个值是Integer.MIN_VALUE相关 JLS

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

于 2012-02-22T15:16:27.677 回答
27

如 JSL 第 3 版中所述,整数存储溢出并且未以任何方式指示。

内置整数运算符不会以任何方式指示上溢或下溢。如果需要对空引用进行NullPointerException拆箱转换(第 5.1.8 节) ,则整数运算符可以抛出。除此之外,唯一可以抛出异常的整数运算符(第 11节)是整数除法运算符/ (第 15.17.2 节)和整数余数运算符% (第 15.17.3 节)ArithmeticException如果右手操作数为零,以及递增和递减运算符++第 15.15.1 节第 15.15.2 节)和--第 15.14.3 节第 15.14.2 节),它们可以引发OutOfMemoryErrorif 装箱转换(第 5.1.7 节)是必需的,并且没有足够的内存来执行转换。

4位存储示例:

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

MAX_INT + 1:

 0111+
 0001
 ----
 1000
于 2012-02-22T15:19:03.190 回答
8

您必须了解整数值如何以二进制形式表示,以及二进制加法的工作原理。Java 使用一种称为二进制补码的表示,其中数字的第一位代表它的符号。每当你给最大的 java Integer 加 1 时,它的位符号为 0,那么它的位符号变为 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

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

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

于 2012-02-22T15:18:28.237 回答
7

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

我相信有一些建议(尴尬的)Java SE 8 库引发溢出,以及未签名的操作。我相信在 DSP 世界中流行的一种行为是将值限制在最大值,所以Integer.MAX_VALUE + 1 == Integer.MAX_VALUE[不是 Java]。

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

于 2012-02-22T15:21:18.620 回答
4

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

于 2012-02-22T15:16:09.540 回答
3

这是一个众所周知的问题,因为整数在二进制层被表示为二进制补码。当您将 1 添加到二进制补码的最大值时,您会得到最小值。老实说,在 java 存在之前,所有整数都以这种方式表现,而为 Java 语言更改这种行为会增加整数数学的开销,并使来自其他语言的程序员感到困惑。

于 2012-02-22T15:19:13.533 回答
2

当您将3(in binary 11) 添加到 1 (in binary ) 时,您必须从右侧开始将所有二进制1更改为0(in binary ) ,直到得到 0,您应该将其更改为. 所有地方都填满了,所以只剩下s。011Integer.MAX_VALUE10

于 2012-02-22T15:18:48.110 回答
0

通过字节示例易于理解=> 在此处输入图像描述

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。值开始围绕类型循环。

整数也是如此。

整数 + 整数也保持整数(与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);
于 2021-04-14T23:33:08.587 回答
-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); 

给出:-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)`

于 2019-05-29T06:29:23.540 回答