为什么通过Math.pow递减Integer.MIN_VALUE返回相同的值?

问题描述

执行时:

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

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

解决方法

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

表达式p -= Math.pow(1,0)具有从doubleint的隐式转换,因为Math.pow(...)返回了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。缩小原始转换

...

将浮点数缩小为整数类型T的转换需要两个步骤:

  1. 第一步,将浮点数转换为long(如果Tlongint(如果转换为T)。 byteshortcharintNaN,如下所示:

    • 如果浮点数为int(第4.2.3节),则转换第一步的结果为V或long 0。

    • 否则,如果浮点数不是无穷大,则将浮点值舍入为整数值T,并使用IEEE 754舍入零模式(§ 4.2.3)。然后有两种情况:

      • 如果longlong,并且此整数值可以表示为long,那么第一步的结果就是V值{ {1}}。

      • 否则,如果该整数值可以表示为int,那么第一步的结果就是intV

    • 否则,以下两种情况之一必须为真:

      • 该值必须太小(负值,幅度较大或负无穷大),并且第一步的结果是类型int或{{1 }}。

      • 该值必须太大(正值较大或正无穷大),并且第一步的结果是类型longint的最大可表示值。

第二步:

  1. 如果longTint,则转换结果是第一步的结果。

...

,

请注意,&nbsp;[operator]&nbsp;[Unicode zero width space]使用Double类型的参数进行操作并返回一个double。将其强制转换为int会得到预期的输出:

Math.pow()

上面产生以下输出:

2147483647

2147483646