(int)Math.pow(2,x) 和 1<<x 的 Java 结果不同
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10416694/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java results differ for (int)Math.pow(2,x) and 1<<x
提问by kasavbere
Why do the following two operations yield different results in Java for x = 31
or 32
but the same results for x=3
?
为什么以下两个操作在 Java 中对x = 31
或产生不同的结果,32
但对 产生相同的结果x=3
?
int x=3;
int b = (int) Math.pow(2,x);
int c = 1<<x;
Results:
结果:
x=32: b=2147483647; c=1;
x=31: b=2147483647; c=-2147483648;
x=3: b=8 ; c=8
回答by NPE
There are multiple issues at play:
有多个问题在起作用:
- An
int
can only store values between-2147483648
and2147483647
. 1 << x
only uses the lowest five bits ofx
. Thus,1 << 32
is by definition the same as1 << 0
.- Shift operations are performed on the two's-complement integer representation of the value of the left operand; this explains why
1 << 31
is negative. Math.pow(2, 32)
returns adouble
.(int)(d)
, whered
is adouble
greater than2147483647
returns2147483647
("the largest representable value of typeint
").
- An
int
只能存储-2147483648
和之间的值2147483647
。 1 << x
只使用 的最低五位x
。因此,1 << 32
根据定义与 相同1 << 0
。- 对左操作数的值的二进制补码整数表示执行移位操作;这解释了为什么
1 << 31
是负面的。 Math.pow(2, 32)
返回一个double
.(int)(d)
,其中d
是一个double
大于2147483647
返回2147483647
(“类型的可表示的最大值int
”)。
What this interview question does is show that (int)Math.pow(2, x)
and 1 << x
are not equivalent for values of x
outside the 0
...30
range.
这个面试问题的作用是表明(int)Math.pow(2, x)
和1 << x
不等同于...范围x
之外的值。0
30
P.S. It is perhaps interesting to note that using long
in place of int
(and 1L
in place of 1
) would give yet another set of results different from the other two. This holds even if the final results are converted to int
.
PS 也许有趣的是,使用long
代替int
(和1L
代替1
)会给出另一组与其他两个不同的结果。即使最终结果转换为int
.
回答by asenovm
According to the documentation Math.pow
will promote both of its arguments to double and return double. Obviously when the returned result is double and you cast it to int you'll get only the highest 32 bits and the rest will be truncated - hence you always get the (int) Math.pow(2,x);
value. When you do bitshift you always work with ints and hence an overflow occurs.
根据文档,Math.pow
将其两个参数都提升为 double 并返回 double。显然,当返回的结果是 double 并且您将其强制转换为 int 时,您只会获得最高的 32 位,其余的将被截断 - 因此您始终会获得该(int) Math.pow(2,x);
值。当您执行 bitshift 时,您总是使用整数,因此会发生溢出。
回答by erikxiv
Consider the limits of the type int. How large a number can it hold?
考虑 int 类型的限制。它可以容纳多大的数字?
回答by mrketchup
int is 32 bits in size and since it is signed (by default), the first bit is used for the sign. When you shift left 31 bits, you get the Two's Compliment, which is -(2^32). When you shift left 32 bits, it just loops all the way back around to 1. If you were to do this shifting with longs instead of ints, you would get the answers you expect (that is until you shift 63+ bits).
int 的大小为 32 位,因为它是有符号的(默认情况下),所以第一位用于符号。当您左移 31 位时,您会得到Two's Compliment,即 -(2^32)。当你左移 32 位时,它只是一直循环回到 1。如果你用 long 而不是 int 来做这个移位,你会得到你期望的答案(直到你移位 63+ 位)。
回答by denine99
Here's a micro-benchmark for the case of a long. On my laptop (2.8GHz), using shift instead of Math.pow
is over 7x faster.
这是一个长期案例的微基准。在我的笔记本电脑 (2.8GHz) 上,使用 shift 而不是Math.pow
快 7 倍。
int limit = 50_000_000;
@Test
public void testPower() {
Random r = new Random(7);
long t = System.currentTimeMillis();
for (int i = 0; i < limit; i++) {
int p = r.nextInt(63);
long l = (long)Math.pow(2,p);
}
long t1 = System.currentTimeMillis();
System.out.println((t1-t)/1000.0); // 3.758 s
}
@Test
public void testShift() {
Random r = new Random(7);
long t = System.currentTimeMillis();
for (int i = 0; i < limit; i++) {
int p = r.nextInt(63);
long l = 1L << p;
}
long t1 = System.currentTimeMillis();
System.out.println((t1-t)/1000.0); // 0.523 s
}