为什么通过 Math.pow() return 递减 Integer.MIN_VALUE 相同的值?

Why does decrementing Integer.MIN_VALUE by Math.pow() return the same value?

执行时:

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

那么为什么 Math.pow() 不会溢出数字?

请注意,Math.pow() 使用 Double 类型的参数,returns 使用双精度类型的参数。将其转换为 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

我们通过观察 -2147483648 == Integer.MIN_VALUE (= -(2³¹)).

开始讨论

表达式 p -= Math.pow(1,0) 具有从 doubleint 的隐式转换,因为 Math.pow(...) returns 和 double。具有显式强制转换的表达式如下所示

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

Ideone demo

再分散一点,我们得到

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

Ideone demo

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

强制转换的行为受 Java 14 JLS, §5.1.3:

控制

5.1.3. Narrowing Primitive Conversion

...

A narrowing conversion of a floating-point number to an integral type T takes two steps:

  1. In the first step, the floating-point number is converted either to a long, if T is long, or to an int, if T is byte, short, char, or int, as follows:

    • If the floating-point number is NaN (§4.2.3), the result of the first step of the conversion is an int or long 0.

    • Otherwise, if the floating-point number is not an infinity, the floating-point value is rounded to an integer value V, rounding toward zero using IEEE 754 round-toward-zero mode (§4.2.3). Then there are two cases:

      • If T is long, and this integer value can be represented as a long, then the result of the first step is the long value V.

      • Otherwise, if this integer value can be represented as an int, then the result of the first step is the int value V.

    • Otherwise, one of the following two cases must be true:

      • The value must be too small (a negative value of large magnitude or negative infinity), and the result of the first step is the smallest representable value of type int or long.

      • The value must be too large (a positive value of large magnitude or positive infinity), and the result of the first step is the largest representable value of type int or long.

In the second step:

  1. If T is int or long, the result of the conversion is the result of the first step.

...