两个整数相乘溢出导致负数

发布于 2024-12-01 20:30:15 字数 514 浏览 1 评论 0原文

考虑 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

活雷疯 2024-12-08 20:30:15

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.

凌乱心跳 2024-12-08 20:30:15

让我们看一下二进制:

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 (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.

In other words, the result overflows for int, and you get what's left.

深爱成瘾 2024-12-08 20:30:15

您可能需要检查整数溢出作为一般概念。
根据语言的不同,溢出和下溢的处理方式也有所不同。这是一篇关于Java 中的整数上溢和下溢的文章。

至于 Java 语言之所以如此,一如既往,这是语言设计的简单性和性能之间的权衡。但在 Java puzzlers(谜题 3)中,作者批评了 Java 中溢出是无声的这一事实:

语言设计者的教训是,减少
静默溢出的可能性
。这可以通过提供支持来完成
对于不会默默溢出的算术。程序可能会抛出
一个异常而不是溢出,就像 Ada 一样,或者他们可以切换
根据需要自动转换为更大的内部表示以避免
溢出,Lisp 也是如此。这两种方法都可能有性能
与他们相关的处罚。另一种降低可能性的方法
无提示溢出的目的是支持目标类型,但这增加了
类型系统非常复杂。

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:

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.

Saygoodbye 2024-12-08 20:30:15

其他一些答案正确地解释了为什么会发生这种情况(即带符号的补码二进制逻辑)。

该问题的实际解决方案以及如何在使用非常大的数字时在 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));

    }

}

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.

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));

    }

}
萌面超妹 2024-12-08 20:30:15

关于整数溢出的原因,其他答案已经解释过了。

确保计算中长算术的一种实用方法是使用带有 l 后缀的数字文字,将文字声明为 long

溢出的普通整数乘法:

jshell> 100000 * 100000
$1 ==> -727379968

被乘数之一带有l后缀的不溢出的乘法:

jshell> 100000 * 100000l
$1 ==> 1000000000000

注意long也容易溢出,但范围要大得多,从 -9,223,372,036,854,775,8089,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 as long.

Ordinary integer multiplication that overflows:

jshell> 100000 * 100000
$1 ==> -727379968

Multiplication where one of the multiplicands has l suffix that does not overflow:

jshell> 100000 * 100000l
$1 ==> 1000000000000

Note that longs 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文