为什么使用 Math.pow() 减去 Integer.MIN_VALUE 会返回相同的值?

3

执行时:

        int p=-2147483648;
        p-=Math.pow(1,0);  
        System.out.println(p);
        p-=1;
        System.out.println(p);
Output: -2147483648
         2147483647 

那么为什么Math.pow()不会导致数值溢出呢?


如果两个参数都是整数,则结果与将第一个参数的值提高到第二个参数的值所得到的数学结果完全相等,前提是该结果确实可以准确地表示为“double”值。您可以在Math javadocs上阅读更多信息 - Luis Galaz
2个回答

5

我们开始讨论观察到 -2147483648 == Integer.MIN_VALUE (= -(2³¹))。

表达式 p -= Math.pow(1,0) 有一个从 doubleint 的隐式转换,因为Math.pow(...) 返回一个 double。 显式转换的表达式如下

p = (int) (p - Math.pow(1,0))

Ideone演示

更加分散,我们得到

double d = p - Math.pow(1,0);
p = (int) d;

Ideone演示

正如我们所看到的,d 的值为 -2.147483649E9 (= -2147483649.0< Integer.MIN_VALUE

强制类型转换的行为受 Java 14 JLS, §5.1.3 规定:

5.1.3. 缩小原始类型转换 将浮点数转换为整数类型 T 的缩小转换需要两个步骤:
第一步,将浮点数转换为long(如果 Tlong),或者转换为int(如果 Tbyteshortcharint)。此过程如下:
- 如果浮点数是 NaN(§4.2.3),则转换的第一步结果为 intlong 的0。 - 否则,如果浮点数不是无穷大,则使用 IEEE 754 round-toward-zero 模式(§4.2.3)将浮点值四舍五入为整数值 V,向零舍入。然后有两种情况: - 如果 Tlong,并且此整数值可以表示为 long,则第一步的结果是 Vlong 值。 - 否则,如果此整数值可以表示为 int,则第一步的结果是Vint 值。 - 否则,以下两种情况之一必须为真: - 值太小(大数量级的负值或负无穷大),第一步的结果是类型 intlong 可以表示的最小值。 - 值太大(大数量级的正值或正无穷大),第一步的结果是类型 intlong 可以表示的最大值。
第二步如下:
- 如果Tintlong,则转换的结果是第一步的结果。
...

1
请注意,Math.pow()的参数类型为Double,返回值为double。将其强制转换为int将会得到预期的输出结果:
public class MyClass {
    public static void main(String args[]) {
        int p=-2147483648;
        p-=(int)Math.pow(1,0);  
        System.out.println(p);
        p-=1;
        System.out.println(p);
    }
}

以上代码会输出以下内容:

2147483647

2147483646


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接