Почему логический сдвиг влево совпадает с арифметическим сдвигом влево?

Я понимаю, что есть похожие вопросы. Но мне любопытно, почему логический сдвиг влево совпадает с арифметическим сдвигом влево.

Я понимаю, что арифметический и логический сдвиг влево технически одинаковы, так как старший бит (старший бит) не сохраняется в обеих операциях, а старший бит заменяется на 0, а все биты просто сдвигаются влево. Но почему мы не можем сохранить старший бит, сдвигая остальные биты, оставленные для арифметического сдвига влево? Арифметический сдвиг вправо сохраняет старший бит для обозначения бита со знаком, так почему же мы не делаем то же самое для арифметического сдвига влево?

Например, в Java: ››› — логический сдвиг вправо, а ›› — арифметический сдвиг вправо, но ‹‹ выполняет как арифметический, так и логический сдвиг влево, даже если знаковый бит не сохраняется.


person Phillip La    schedule 14.07.2021    source источник
comment
Сдвиг влево на 1 заменяет самый значащий бит на предыдущий второй по значимости бит - он заменяет наименьший значащий бит на 0. Конечно, ничто не мешает вам определить свою собственную операцию. который выполняет сдвиг влево, сохраняя младший значащий бит, но это недостаточно полезная операция, чтобы быть примитивной в любом популярном языке.   -  person kaya3    schedule 14.07.2021
comment
См. также: en.wikipedia.org/wiki/   -  person kaya3    schedule 14.07.2021
comment
Итак, если я правильно понимаю, при арифметическом сдвиге вправо старший бит сохраняется, потому что старший бит 1 будет интерпретироваться как отрицательный знак, а 0 будет интерпретироваться как положительный знак. Если это так, то почему мы не можем сделать то же самое для арифметических сдвигов влево?   -  person Phillip La    schedule 14.07.2021
comment
Когда мы выполняем арифметический сдвиг влево, разве мы не хотим, чтобы отрицательное число тоже оставалось отрицательным? Поскольку сдвиг влево эквивалентен делению на 2? Если мы просто сдвинемся влево и в некоторых случаях удалим старший бит 1 со вторым старшим битом 0, разве мы не изменим знак числа?   -  person Phillip La    schedule 14.07.2021
comment
Если вы сдвинетесь влево так, что отрицательное число превратится в положительное, то вы получите тот же результат, что и при умножении на 2; в любом случае это целочисленное переполнение, и вы не получите правильный ответ, потому что фиксированной ширины целого числа недостаточно для представления правильного ответа. Если вместо этого вы сохранили бит знака, то вы все равно не получите правильный ответ для умножения на 2 по той же причине - вы просто получите неправильный отрицательный результат вместо неправильного положительного результата.   -  person kaya3    schedule 14.07.2021
comment
Поскольку сдвиг влево эквивалентен делению на 2? - нет, сдвиг влево (на 1 бит) эквивалентен умножению на 2. Для любого int x ни x*2 и x+x сохраняют знаковый бит, так почему эквивалентная операция x<<1 должна сохранять его?   -  person Thomas Kläger    schedule 14.07.2021


Ответы (2)


Но почему мы не можем сохранить старший бит, сдвигая остальные биты, оставленные для арифметического сдвига влево?

Мы могли бы это сделать, например, вот реализация этой идеи на Java:

int shiftLeftPreserveMSB(int x, int k) {
    return (x & Integer.MIN_VALUE) | ((x << k) & Integer.MAX_VALUE);
}

Но действительно ли это полезно? Например, у него есть сомнительное свойство: всякий раз, когда результат отличается от x << k, ни один из результатов не соответствует (long)x << k. С арифметической точки зрения это не очень удобно. Может быть, это так, но, по крайней мере, это странная операция. Для такой операции могут быть другие применения, например, в битхаках, хотя я не знаю ни одного такого использования.

person harold    schedule 14.07.2021

Обычные арифметические сдвиги влево и вправо сохраняют знаковые биты. Так

-32 >> 1 == -16
-16 << 1 == -32

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

Но логический сдвиг вправо должен быть обработан специально, чтобы сдвинуть знаковый бит и заполнить слева 0 битами.

-1 >>> 1 == 2147483647

Это важно, если необходимо выполнить неарифметические манипуляции с битами. Но как сделать арифметический сдвиг влево, сохраняющий знак?

Рассмотрим 4-битный регистр, а msb — это знак, и он сохраняется. Представьте, что оператор << работает следующим образом.

0111 == 7
0111 << 1 == 0110 == 6
0110 << 1 == 0100 == 4
0100 << 1 == 0000 == 0

Имхо, толку от этого не будет.

person WJS    schedule 14.07.2021