java 两个整数相乘溢出导致负数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7215411/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Multiplication of two ints overflowing to result in a negative number
提问by user900721
Consider this snippet from the Java language specification.
考虑来自 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);
}
}
The output is
输出是
-727379968
1000000000000
Why is the result -727379968
for (i*i)
? Ideally it should be 1000000000000.
为什么结果-727379968
是(i*i)
?理想情况下,它应该是 1000000000000。
I know the range of Integer is from –2147483648 to 2147483647. so obviously 1000000000000 is not in the given range.
我知道 Integer 的范围是从 –2147483648 到 2147483647。所以很明显 1000000000000 不在给定的范围内。
Why does the result become -727379968
?
结果为什么变成了-727379968
?
回答by Ernest Friedman-Hill
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.
Java(像现在的大多数计算机架构一样)使用一种称为二进制补码算法的东西,它使用整数的最高有效位来表示一个数字是负数。如果你将两个大数字相乘,你最终会得到一个大到设置最高位的数字,结果最终为负。
回答by JRL
You might want to check Integer overflowas 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.
您可能想要检查整数溢出作为一般概念。上溢和下溢的处理方式也因语言而异。这是一篇关于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 语言中如此,一如既往,这是语言设计的简单性和性能之间的权衡。但在Java 谜题(谜题 3)中,作者批评了 Java 中溢出是无声的这一事实:
The lesson for language designers is that it may be worth reducing the likelihood of silent overflow. This could be done by providing support for arithmatic that does not overflow silently. Programs could throw an exception instead of overflowing, as does Ada, or they could switch to a larger internal representation automatically as required to avoid overflow, as does Lisp. Both of these approaches may have performance penalties associated with them. Another way to reduce the likelyhood of silent overflow is to support target typing, but this adds significant complexity to the type system.
给语言设计者的教训是,减少无声溢出的可能性可能是值得的。这可以通过为不会静默溢出的算术提供支持来实现。程序可以抛出异常而不是像 Ada 那样溢出,或者它们可以根据需要自动切换到更大的内部表示以避免溢出,就像 Lisp 那样。这两种方法都可能有与之相关的性能损失。另一种减少无提示溢出可能性的方法是支持目标类型,但这会显着增加类型系统的复杂性。
回答by dlev
Lets look at the binary:
让我们看一下二进制文件:
1000000 is 1111 0100 0010 0100 0000
.
1000000000000 is 1110 1000 1101 0100 1010 0101 0001 0000 0000 0000
1000000 是1111 0100 0010 0100 0000
.
1000000000000 是1110 1000 1101 0100 1010 0101 0001 0000 0000 0000
However, the first two sections of 4 bits won't fitin an int
(since int
is 32-bits wide in Java,) and so they are dropped, leaving only 1101 0100 1010 0101 0001 0000 0000 0000
, which is -727379968
.
然而,4位的前两个部分将不适合在一个int
(因为int
是32位宽在Java中,),因此它们都将被丢弃,只留下1101 0100 1010 0101 0001 0000 0000 0000
,这是-727379968
。
In other words, the result overflows for int
, and you get what's left.
换句话说,结果溢出 for int
,你得到剩下的。
回答by Craig S. Dickson
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.
该问题的实际解决方案以及在使用非常大的数字时如何在 Java 中获得正确答案是使用 BigInteger 类,该类也适用于长值。
package com.craigsdickson.scratchpad;
import java.math.BigInteger;
public class BigIntegerExample {
public static void main(String[] args) {
int bigInt = Integer.MAX_VALUE;
// prints incorrect answer
System.out.println(bigInt * bigInt);
BigInteger bi = BigInteger.valueOf(bigInt);
// prints correct answer
System.out.println(bi.multiply(bi));
long bigLong = Long.MAX_VALUE;
// prints incorrect answer
System.out.println(bigLong * bigLong);
BigInteger bl = BigInteger.valueOf(bigLong);
// prints correct answer
System.out.println(bl.multiply(bl));
}
}
回答by mrts
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 as long
.
在计算中确保长算术的一种实用方法是使用带有l
后缀的数字文字,将文字声明为long
.
Ordinary integer multiplication that overflows:
溢出的普通整数乘法:
jshell> 100000 * 100000
==> -727379968
Multiplication where one of the multiplicands has l
suffix that does not overflow:
被乘数之一具有l
不溢出后缀的乘法:
jshell> 100000 * 100000l
==> 1000000000000
Note that long
s are also prone to overflow, but the range is much greater, from -9,223,372,036,854,775,808
to 9,223,372,036,854,775,807
.
请注意,long
s 也容易溢出,但范围要大得多,从-9,223,372,036,854,775,808
到9,223,372,036,854,775,807
。