(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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 00:58:25  来源:igfitidea点击:

Java results differ for (int)Math.pow(2,x) and 1<<x

javabitwise-operatorsbit-shift

提问by kasavbere

Why do the following two operations yield different results in Java for x = 31or 32but 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:

有多个问题在起作用:

What this interview question does is show that (int)Math.pow(2, x)and 1 << xare not equivalent for values of xoutside the 0...30range.

这个面试问题的作用是表明(int)Math.pow(2, x)1 << x不等同于...范围x之外的值。030

P.S. It is perhaps interesting to note that using longin place of int(and 1Lin 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.powwill 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.powis 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
}