Java 铸造Math.pow()时的精度损失

Java 铸造Math.pow()时的精度损失,java,casting,int,Java,Casting,Int,我试图计算int的最大值,但是我不明白为什么转换为int的计算值低于转换为long时的值。我在计算器上提出了(2^31)-1,值为 2_147_483_647 在Java中,当我上升2^31并扣除1时,它应该计算int2147483647的最大值,但它没有 System.out.println(((long) Math.pow(2, 31)) - 1); System.out.println((int) Math.pow(2, 31) - 1); 第一次计算得出:2\u 147\u 48

我试图计算int的最大值,但是我不明白为什么转换为int的计算值低于转换为long时的值。我在计算器上提出了
(2^31)-1
,值为

2_147_483_647
在Java中,当我上升
2^31
并扣除
1
时,它应该计算int
2147483647
的最大值,但它没有

System.out.println(((long) Math.pow(2, 31)) - 1); 
System.out.println((int) Math.pow(2, 31) - 1); 
第一次计算得出:
2\u 147\u 483\u 647


第二次计算给出:
2\u 147\u 483\u 646
键入整个
Math.pow(2,31)-1)
。像这样

System.out.println((int) (Math.pow(2, 31) - 1));

你把括号放错地方了。应该是:

System.out.println((int) (Math.pow(2, 31) - 1));

强制转换优先于减法。你应该先做减法:

 System.out.println((int) (Math.pow(2, 31) - 1)); 
  • Math.pow(2,31)
    2_147_483_648
    的类型为
    double
    (因为Math.pow()返回一个double),这个数字不适合整数

  • 当您将双精度
    2_147_483_648
    转换为整数时,它将被截断为整数所能容纳的最大值(请参阅)

  • 强制转换将双精度
    2_147_483_648
    截断为int
    2_147_483_647

  • 然后代码减去1,最后得到
    2\u 147\u 483\u 646
第一个示例 让我们分析一下你做了什么。第一个例子是

((long) Math.pow(2, 31)) - 1;
这意味着您首先计算
Math.pow(2,31)
,这将产生

2.147_483_648 E9
之后,您将强制转换为
long
。请注意,
long
对于该值有足够的位置,因此它表示为

2_147_483_648
然后减去
1
,得到

2_147_483_647
2_147_483_646

第二个例子 现在,让我们看看第二个示例的作用。你写的

(int) Math.pow(2, 31) - 1
这被解释为

((int) Math.pow(2, 31)) - 1
因此,与之前相同,但强制转换为
int
,而不是
long
。现在请注意,
int
没有足够的位置来放置该值。可以表示的最大
int

2_147_483_647 // MAX_INTEGER
所以你也会得到这个值。然后减去
1
,得到

2_147_483_647
2_147_483_646

校正 我想你是这么想的

(int) Math.pow(2, 31) - 1
评估为

(int) (Math.pow(2, 31) - 1)
但事实并非如此。如果你把这一点说得很清楚,你就会明白

2_147_483_647
正如所料


运算符优先级 您可以在Java语言规范中了解这一点,请参阅。强制转换的优先级高于减法等运算符

这是因为强制转换是一个一元运算符,而减法是二元运算符。一元优先于二元。因此,下表概述如下:

+----------------------------------------------------------------+
| Operators             | Precedence (top is high, bottom low)   |
|-----------------------|----------------------------------------|
| postfix               | expr++ expr--                          |
| unary                 | ++expr --expr +expr -expr ~ !          |
| multiplicative        | * / %                                  |
| additive              | + -                                    |
| shift                 | << >> >>>                              |
| relational            | < > <= >= instanceof                   |
| equality              | == !=                                  |
| bitwise AND           | &                                      |
| bitwise exclusive OR  | ^                                      |
| bitwise inclusive OR  | |                                      |
| logical AND           | &&                                     |
| logical OR            | ||                                     |
| ternary               | ? :                                    |
| assignment            | = += -= *= /= %= &= ^= |= <<= >>= >>>= |
+----------------------------------------------------------------+
+----------------------------------------------------------------+
|运算符|优先级(顶部为高,底部为低)|
|-----------------------|----------------------------------------|
|后缀| expr++expr--|
|一元|++expr--expr+expr-expr~|
|乘法|*/%|
|加法|+-|
|班次|>>>>|
|关系|<>=实例|
|相等|==!=|
|按位与|&|
|位异或|^|
|按位包含或| ||
|逻辑与&&|
|逻辑或| | ||
|三元|?:|
|分配|=+=-=*=/=%=&=^=|===>>=|
+----------------------------------------------------------------+

Casting当然是unitary类别的一部分。

像这样编写代码
(int)Math.pow(2,31)-1
使Java将
Math.pow(2,31)
转换为int。因为这超过了int的最大值,结果是
2_147_483_647
。因为之后减去1,所以得到的值低于实际解。 您应该将整个计算转换为int,而不仅仅是
Math.pow(2,31)
,因此它看起来是这样的:
(int)(Math.pow(2,31)-1)

Java在释放double->int时不会溢出,这就是为什么数学没有检查的原因