英文:
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);
输出:-2147483648
2147483647
那么为什么 Math.pow() 不会使数字溢出呢?
英文:
on executing :
int p=-2147483648;
p-=Math.pow(1,0);
System.out.println(p);
p-=1;
System.out.println(p);
Output: -2147483648
2147483647
So why doesn't Math.pow() overflow the number?
答案1
得分: 5
我们通过观察发现,-2147483648 == Integer.MIN_VALUE
(= -(2的31次方))。
表达式p -= Math.pow(1,0)
在Math.pow(...)
返回一个double
,因此存在从double
到int
的隐式转换。带有显式转换的表达式如下:
p = (int) (p - Math.pow(1,0));
进一步展开,我们得到
double d = p - Math.pow(1,0);
p = (int) d;
正如我们所见,d
的值为-2.147483649E9
(= -2147483649.0
),小于Integer.MIN_VALUE
。
转换的行为受Java 14 JLS,§5.1.3控制:
5.1.3. 缩窄的基本类型转换
...
将浮点数转换为整数类型T
的缩窄转换分为两步:
在第一步中,根据以下规则,将浮点数转换为
long
(如果T
是long
)或int
(如果T
是byte
、short
、char
或int
):
如果浮点数是
NaN
(§4.2.3),转换的第一步结果为int
或long
的0。否则,如果浮点数不是无穷大,将浮点值四舍五入为整数值
V
,使用IEEE 754的向零舍入模式(§4.2.3)。然后有两种情况:
如果
T
是long
,并且这个整数值可以表示为long
,则第一步的结果是long
值V
。否则,如果这个整数值可以表示为
int
,则第一步的结果是int
值V
。否则,以下两种情况之一必须为真:
值必须太小(具有较大幅度的负值或负无穷大),第一步的结果是可表示的
int
或long
类型的最小值。值必须太大(具有较大幅度的正值或正无穷大),第一步的结果是可表示的
int
或long
类型的最大值。在第二步中:
- 如果
T
是int
或long
,则转换的结果是第一步的结果。
...
英文:
We start the discussion by observing that -2147483648 == Integer.MIN_VALUE
(= -(2³¹)).
The expression p -= Math.pow(1,0)
has an implicit cast from double
to int
since Math.pow(...)
returns a double
. The expression with an explicit cast looks like this
p = (int) (p - Math.pow(1,0))
Even more spread out, we get
double d = p - Math.pow(1,0);
p = (int) d;
As we can see, d
has the value -2.147483649E9
(= -2147483649.0
) < Integer.MIN_VALUE
.
The behaviour of the cast is governed by 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.
>
> ...
答案2
得分: 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
英文:
Please note that Math.pow()
operates with arguments of type Double and returns a double. Casting it to int will result in the expected output:
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);
}
}
The above produces the following output:
2147483647
2147483646
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论