Java 在评估长算术表达式时如何处理中间值?

问题描述 投票:0回答:2

我想知道 Java 在计算数学表达式时如何处理中间值,特别是当中间值超过其存储大小时。例如,

int a = 1103515245;
int x = 1013904223;
int c = 2531011;

x = (a*x + c) & 0x7FFFFFFF; //  to make sure x will remain a positive integer.

现在,我的问题是在计算

a*x
时,它的值超出了整数范围(即使在加法过程中也可能发生),Java编译器是如何处理的

谢谢。

java integer-overflow arithmetic-expressions
2个回答
1
投票

JLS 15.17.1

如果整数乘法溢出,则结果是数学乘积的低位,以某种足够大的二进制补码格式表示。

JLS 15.18.2

如果整数加法溢出,则结果是数学和的低位位,以某种足够大的二进制补码格式表示。

这与 C 形成对比,后者以不采用二进制补码架构而著称,并将带符号类型的溢出视为未定义行为。


1
投票

每个中间值都有一个类型,除非你显式地强制转换它,否则它将是中间计算将产生的类型,因此 int * int 将产生另一个 int 而 int * float 将产生另一个 float 并且立即值的溢出将相应发生。这样的计算本质上将被解构为类似

int a = 1103515245;
int x = 1013904223;
int c = 2531011;

x = a*x;
x = x + c;
x = x & 0x7FFFFFFF;

这并不是编译器真正做的事情,因为它会生成在堆栈计算机上运行的 JVM 字节码,但您可以粗略地想象它在做一些更接近该代码而不是您的代码的事情。这并没有什么神奇之处。溢出会发生,就像它们在我在代码示例中编写的分解操作中一样。如果你想避免溢出,你需要将一个或两个输入值转换为一些中间计算到更大的数据类型,如 long。在这里要小心,因为仅仅转换结果并不能解决问题。然后它会先溢出,然后将溢出的值进行转换。

© www.soinside.com 2019 - 2024. All rights reserved.