我正在编写我自己的权力函数实现,我发现了一些在Integer.MAX_VALUE
周围发生的奇怪结果,我不知道为什么会发生这些结果。这就是我的实现:
public static long power(long x, long y) {
int result = 1;
while (y > 0) {
if ((y & 1) == 0) {
x *= x;
y >>>= 1;
} else {
result *= x;
y--;
}
}
return result;
}
运行以下代码,
System.out.println(fastPower(2, 31));
System.out.println(Math.pow(2, 31);
System.out.println((long)Math.pow(2, 31));
System.out.println((int)Math.pow(2, 31));
结果如下,我不明白。
-2147483648
2.147483648E9
2147483648
2147483647
这进一步使我在使用short
s时感到困惑:
System.out.println(fastPower(2, 15));
System.out.println(Math.pow(2, 15));
System.out.println((int)Math.pow(2, 15));
System.out.println((short)Math.pow(2,15));
32768
32768.0
32768
-32768
这些都是我所期望的答案,但它们似乎与int
的结果不一致。
发布于 2018-06-09 08:15:19
int
和short
的前三个输出很容易解释:
-2147483648 // your method returns an int, so overflows
2.147483648E9 // Math.pow returns a double, so formatted like this
2147483648 // double casted to a long, 2147483648 inside the possible range for long
32768 // your method returns an int, 32768 is inside the possible range for int
32768.0 // Math.pow returns a double, so formatted like this
32768 // double casted to an int, 32768 is inside the possible range for int
难以解释的是第四个结果。System.out.println((int)Math.pow(2, 31));
不也应该打印-2147483648吗?
这里的诀窍是Java如何实现从double
到int
的转换。根据规范,这称为收缩原语转换(第5.1.3节):
22对原语类型的特定转换称为缩窄原语转换:
这就是如何执行double
到int
的转换(由我用粗体表示):
在第一步中,浮点数被转换成一个长的,如果T是长的,或者一个int,如果T是字节、短、字符或int,如下所示:
如果T是长的,并且这个整数值可以表示为长,那么第一步的结果是长值V.b。否则,如果这个整数值可以表示为int,那么第一步的结果就是int值V。
1. In the second step:
第一步将double更改为int
- 2147483647的最大可表示值。这就是为什么在int
中,2147483647被打印出来的原因。在short
情况下,第二步将int
值2147483647更改为short
,如下所示:
缩小符号整数到整型T的转换只会丢弃除n个最低阶位外的所有比特,其中n是用来表示T型的位数。
这就是为什么short
飞越,但int
没有!
发布于 2018-06-09 08:15:41
假设power()
和fastPower()
是相同的,则fastPower(2, 31)
返回-2147483648
,因为result
变量是int
,尽管参数和返回类型都是long
。
Math.pow()
返回一个double
,因此将结果转换为整数类型(long
、int
、short
、byte
、char
)遵循下面引用的JLS 5.1.3.缩窄本原转换规则。
Math.pow(2, 31)
是2147483648.0
。当转换为long
时,它的值是相同的,即2147483648
。然而,当转换为int
时,值太大,因此结果是Integer.MAX_VALUE
,即2147483647
,如下面引号中所强调的那样。
Math.pow(2, 15)
是32768.0
。当转换为int
时,它的值是相同的,即32768
。然而,当转换到short
时,值首先缩小到int
,然后通过丢弃更高的位(参见下面的第二个引号)缩小到short
,从而导致数字溢出到-32768
。
将浮点数转换为整型T的缩窄转换需要两个步骤:
int
,,则将浮点数转换为long
,如果T为byte
、short
、char
或int
,则将转换为long
,如下所示:- If the floating-point number is NaN ([§4.2.3](https://docs.oracle.com/javase/specs/jls/se10/html/jls-4.html#jls-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](https://docs.oracle.com/javase/specs/jls/se10/html/jls-4.html#jls-4.2.3)). Then there are two cases:
1. 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`.
2. 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:
1. 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`.
2. **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`****.**
- If T is `int` or `long`, the result of the conversion is the result of the first step.
- If T is `byte`, `char`, or `short`, the result of the conversion is the result of a narrowing conversion to type T ([§5.1.3](https://docs.oracle.com/javase/specs/jls/se10/html/jls-5.html#jls-5.1.3)) of the result of the first step.
将有符号整数转换为整数类型T只会丢弃除n个最低阶位之外的所有位数,其中n是用来表示T型的位数,除了可能丢失关于数值大小的信息外,这还可能导致结果值的符号与输入值的符号不同。
https://stackoverflow.com/questions/50775768
复制