9

为什么以下两个操作在 Java 中会产生不同的结果,x = 31或者32会产生相同的结果x=3

int x=3;
int b = (int) Math.pow(2,x);
int c = 1<<x;

结果:

x=32: b=2147483647; c=1;
x=31: b=2147483647; c=-2147483648;
x=3:  b=8         ; c=8

考虑 int 类型的限制。它可以容纳多大的数字?

4

5 回答 5

20

有多个问题在起作用:

这个面试问题的作用是表明(int)Math.pow(2, x)并且对于超出...范围1 << x的值是不等价的。x030

PS 有趣的是,使用longin place of int(和1Lin place of 1)会给出另一组与其他两个不同的结果。即使最终结果转换为int.

于 2012-05-02T15:29:06.083 回答
3

根据文档,Math.pow将把它的两个参数都提升为双倍并返回双倍。显然,当返回的结果为 double 并且您将其转换为 int 时,您将只获得最高的 32 位,其余的将被截断 - 因此您始终会获得该(int) Math.pow(2,x);值。当您进行位移时,您总是使用整数,因此会发生溢出。

于 2012-05-02T15:24:15.363 回答
2

考虑 int 类型的限制。它可以容纳多大的数字?

于 2012-05-02T15:22:31.803 回答
1

这是一个长期案例的微基准。在我的笔记本电脑 (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
}
于 2017-08-10T01:03:31.163 回答
0

int 大小为 32 位,并且由于它是有符号的(默认情况下),因此第一位用于符号。当您向左移动 31 位时,您会得到Two's Compliment,即 -(2^32)。当您向左移动 32 位时,它只会一直循环回到 1。如果您要使用 long 而不是 int 进行这种移动,您会得到您期望的答案(即直到您移动 63+ 位)。

于 2012-05-02T15:35:07.487 回答