两个整数相乘溢出导致负数
考虑 Java 语言规范中的这段代码。
class Test {
public static void main(String[] args) {
int i = 1000000;
System.out.println(i * i);
long l = i;
System.out.println(l * l);
}
}
输出为
-727379968
1000000000000
Why is the result -727379968
for (i*i)
?理想情况下它应该是 1000000000000。
我知道 Integer 的范围是从 –2147483648 到 2147483647。所以显然 1000000000000 不在给定范围内。
为什么结果会变成-727379968
?
Consider this snippet from the Java language specification.
class Test {
public static void main(String[] args) {
int i = 1000000;
System.out.println(i * i);
long l = i;
System.out.println(l * l);
}
}
The output is
-727379968
1000000000000
Why is the result -727379968
for (i*i)
? Ideally it should be 1000000000000.
I know the range of Integer is from –2147483648 to 2147483647. so obviously 1000000000000
is not in the given range.
Why does the result become -727379968
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
Java(像当今大多数计算机体系结构一样)使用一种称为二进制补码算术的东西,它使用整数的最高有效位来表示数字为负数。如果将两个大数相乘,最终会得到一个非常大的数,以至于设置了最高位,结果最终为负数。
Java (like most computer architectures these days) uses something called two's complement arithmetic, which uses the most significant bit of an integer to signify that a number is negative. If you multiply two big numbers, you end up with a number that's so big it sets that highest bit, and the result ends up negative.
让我们看一下二进制:
1000000 是
1111 0100 0010 0100 0000
。1000000000000 是
1110 1000 1101 0100 1010 0101 0001 0000 0000 0000
但是,4 位的前两部分不适合在
int
中(因为int
是 32 位在 Java 中很宽),因此它们被删除,只留下1101 0100 1010 0101 0001 0000 0000 0000
,即-727379968
。换句话说,结果溢出了
int
,而您得到了剩下的内容。Lets look at the binary:
1000000 is
1111 0100 0010 0100 0000
.1000000000000 is
1110 1000 1101 0100 1010 0101 0001 0000 0000 0000
However, the first two sections of 4 bits won't fit in an
int
(sinceint
is 32-bits wide in Java,) and so they are dropped, leaving only1101 0100 1010 0101 0001 0000 0000 0000
, which is-727379968
.In other words, the result overflows for
int
, and you get what's left.您可能需要检查整数溢出作为一般概念。
根据语言的不同,溢出和下溢的处理方式也有所不同。这是一篇关于Java 中的整数上溢和下溢的文章。
至于 Java 语言之所以如此,一如既往,这是语言设计的简单性和性能之间的权衡。但在 Java puzzlers(谜题 3)中,作者批评了 Java 中溢出是无声的这一事实:
You might want to check Integer overflow as a general concept.
Overflow and underflow are handled differently depending on the language, too. Here is an article on Integer overflow and underflow in Java.
As for the reason why this is so in the Java language, as always, it's a tradeoff between simplicity in the language design and performance. But in Java puzzlers (puzzle 3), the authors criticize the fact that overflows are silent in Java:
其他一些答案正确地解释了为什么会发生这种情况(即带符号的补码二进制逻辑)。
该问题的实际解决方案以及如何在使用非常大的数字时在 Java 中获得正确答案是使用 BigInteger 类,该类也适用于长值。
Some of the other answers explain correctly why this is happening (ie. signed two's compliment binary logic).
The actual solution to the problem and how to get the correct answer in Java when using really big numbers is to use the BigInteger class, which also works for long values.
关于整数溢出的原因,其他答案已经解释过了。
确保计算中长算术的一种实用方法是使用带有
l
后缀的数字文字,将文字声明为long
。溢出的普通整数乘法:
被乘数之一带有
l
后缀的不溢出的乘法:注意
long
也容易溢出,但范围要大得多,从-9,223,372,036,854,775,808
到9,223,372,036,854,775,807
。The reasons why integer overflow occurs have already been explained in other answers.
A practical way to ensure long arithmetic in calculations is to use numeric literals with
l
suffix that declare the literals aslong
.Ordinary integer multiplication that overflows:
Multiplication where one of the multiplicands has
l
suffix that does not overflow:Note that
long
s are also prone to overflow, but the range is much greater, from-9,223,372,036,854,775,808
to9,223,372,036,854,775,807
.