JS. Неожиданное поведение при побитовом сдвиге влево (<<)
var a = 0b00000000000000000000000000000001 // 1
var b = a << 31 // -2147483648 (Логично, мы сдвинули биты на 31 влево)
var c = b << 1 // 0 (Тоже логично, единица вышла за пределы 32-х битного числа)
var d = a << 32 // 1
Ожидалось, что последняя строчка приравняет d = 0, ведь инструкция гласит: "a<<b Сдвигает двоичное представление a на b битов влево, добавляя справа нули".
> 1 << 32
1
> (1 << 31) << 1
0
Чем это вызвано и как этого избежать?
Ответы (2 шт):
Автор решения: Ростислав
→ Ссылка
Ответ на тот же вопрос в Java натолкнул меня на мысль, что если правая часть "<<" превышает 31, то от нее берется остаток от деления на 32, который и является итоговым сдвигом. Поэтому
(1<<32) == (1<<0); // Это истина
Избежать этого можно, если добавить проверку
if(b < 32) d = a << b; else d = 0;
Автор решения: Grundy
→ Ссылка
Согласно спецификации, при сдвиге влево (x << y), для чисел
- первый операнд приводится к Int32
- второй операнд приводится к UInt32
- от второго операнда берутся последние 5 бит (
y & 0x1F) - на полученный результат и происходит сдвиг
Возвращаясь к примеру в вопросе:
a << 32
3210=1000002
Последние 5 бит от 32 - 0
Таким образом происходит сдвиг на 0 бит - как результат: значение a как было 1, так и осталось.