В информатике логический сдвиг — это побитовая операция , которая сдвигает все биты своего операнда. Двумя базовыми вариантами являются логический сдвиг влево и логический сдвиг вправо . Это дополнительно модулируется числом позиций бит, на которые должно быть сдвинуто заданное значение, например, сдвиг влево на 1 или сдвиг вправо на n . В отличие от арифметического сдвига , логический сдвиг не сохраняет бит знака числа и не отличает показатель числа от его мантиссы (мантиссы); каждый бит в операнде просто перемещается на заданное число позиций бит, а свободные позиции бит заполняются, как правило, нулями и, возможно, единицами (в отличие от циклического сдвига ).
Логический сдвиг часто используется, когда его операнд рассматривается как последовательность битов, а не как число.
Логические сдвиги могут быть полезны как эффективные способы выполнения умножения или деления беззнаковых целых чисел на степени двойки. Сдвиг влево на n бит в двоичном числе со знаком или без знака приводит к его умножению на 2 n . Сдвиг вправо на n бит в двоичном числе без знака приводит к его делению на 2 n (округление к 0).
Логический сдвиг вправо отличается от арифметического сдвига вправо. Таким образом, во многих языках для них есть разные операторы . Например, в Java и JavaScript логический оператор сдвига вправо — >>> , но арифметический оператор сдвига вправо — >> . (В Java есть только один оператор сдвига влево ( << ), поскольку сдвиг влево с помощью логики и арифметики имеет одинаковый эффект.)
Однако в языках программирования C, C++ и Go есть только один оператор сдвига вправо, >> . Большинство реализаций C и C ++ , а также Go выбирают, какой сдвиг вправо выполнять, в зависимости от типа сдвигаемого целого числа: целые числа со знаком сдвигаются с использованием арифметического сдвига, а целые числа без знака сдвигаются с использованием логического сдвига. В частности, C++ использует свои операторы логического сдвига как часть синтаксиса своих функций ввода и вывода, называемых «cin» и «cout» соответственно.
Все актуальные в настоящее время стандарты C (ISO/IEC 9899:1999 по 2011) оставляют пробел в определении для случаев, когда количество сдвигов равно или больше количества бит в операндах таким образом, что результат не определен. Это позволяет компиляторам C выдавать эффективный код для различных платформ, позволяя напрямую использовать собственные инструкции сдвига, которые имеют различное поведение. Например, shift-left-word в PowerPC выбирает более интуитивное поведение, при котором сдвиг на ширину бит или выше дает ноль, [6] тогда как SHL в x86 выбирает маскировку величины сдвига в младшие биты , чтобы сократить максимальное время выполнения инструкций , и, таким образом, сдвиг на ширину бит не изменяет значение. [7]
Некоторые языки, такие как .NET Framework и LLVM , также оставляют сдвиг на битовую ширину и выше неопределенным (.NET) [8] или неопределенным (LLVM). [9] Другие предпочитают указывать поведение своих наиболее распространенных целевых платформ, таких как C# , который определяет поведение x86. [10]
Если последовательность бит 0001 0111 (десятичное 23) логически сдвинуть на одну битовую позицию, то:
Примечание: MSB = старший значащий бит, LSB = младший значащий бит