Вопрос по java – Результаты Java отличаются для (int) Math.pow (2, x) и 1 << x

8

Почему следующие две операции дают разные результаты в 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
Тонкая разница в том, что Pow ()much медленнее, даже если ответ тот же. pow () имеет ошибку округления, тогда какint переполнен Ты можешь попробовать1L << 32 что равно2147483648 Peter Lawrey

Ваш Ответ

5   ответов
0

int имеет размер 32 бита, и поскольку он подписан (по умолчанию), для знака используется первый бит. Когда вы сдвигаете влево на 31 бит, вы получаетеДва комплимента, который является - (2 ^ 32). Когда вы сдвигаете влево на 32 бита, он просто возвращается назад к 1. Если бы вы делали это с помощью длинных, а не целых чисел, вы получите ожидаемые ответы (то есть, пока вы не сдвинете более 63 бит).

0

Вот микробенчмарк для случая длинного. На моем ноутбуке (2,8 ГГц), используя сдвиг вместо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
}
3

Согласно документацииMath.pow будет продвигать оба своих аргумента для удвоения и возврата double. Очевидно, что когда возвращаемый результат удваивается и вы приводите его к типу int, вы получаете только старшие 32 бита, а остальные будут усечены - следовательно, вы всегда получаете(int) Math.pow(2,x); значение. Когда вы делаете bithift, вы всегда работаете с целыми числами, и, следовательно, происходит переполнение.

Я предполагаю старшие 32 бита мантиссы. Я могу ошибаться, хотя.
Хм, хорошо, это может быть правдой. Я просто вспомнил, чтобы всегда возвращаться2^31-1, Убрал комментарий :)
18

Есть несколько проблем в игре:

Этот вопрос интервью показывает, что(int)Math.pow(2, x) а также1 << x не эквивалентны для значенийx вне0...30 спектр.

Постскриптум Интересно отметить, что использованиеlong на местеint (а также1L на месте1) даст еще один набор результатов, отличный от двух других. Это верно, даже если окончательные результаты преобразованы вint.

Особенно последний пункт очень важен.
2

Вопрос о разнице между левым сдвигом и явными степенями 2.
И добавить к пределуint тот факт, что это подписанный тип.

Похожие вопросы