В комбинаторной математике циклический сдвиг — это операция перестановки записей в кортеже , либо путем перемещения последней записи на первую позицию, при этом сдвигая все остальные записи на следующую позицию, либо путем выполнения обратной операции. Циклический сдвиг — это особый вид циклической перестановки , которая в свою очередь является особым видом перестановки . Формально циклический сдвиг — это перестановка σ n записей в кортеже, такая, что либо
или
Результат многократного применения циклических сдвигов к данному кортежу также называется циклическими сдвигами кортежа.
Например, многократное применение циклических сдвигов к четверке ( a , b , c , d ) дает
и затем последовательность повторяется; таким образом, этот четырехкортеж имеет четыре различных циклических сдвига. Однако не все n -кортежи имеют n различных циклических сдвигов . Например, 4-кортеж ( a , b , a , b ) имеет только 2 различных циклических сдвига. Количество различных циклических сдвигов n -кортежа равно , где k является делителем n , что указывает на максимальное количество повторений по всем подшаблонам.
В программировании побитовое вращение , также известное как циклический сдвиг, — это побитовая операция, которая сдвигает все биты своего операнда. В отличие от арифметического сдвига , циклический сдвиг не сохраняет знаковый бит числа и не отличает показатель степени числа с плавающей точкой от его мантиссы . В отличие от логического сдвига , вакантные позиции бит не заполняются нулями, а заполняются битами, которые были сдвинуты из последовательности.
Циклические сдвиги часто используются в криптографии для перестановки битовых последовательностей. К сожалению, многие языки программирования, включая C , не имеют операторов или стандартных функций для циклического сдвига, хотя практически все процессоры имеют побитовые инструкции для этого (например, Intel x86 имеет ROL и ROR). Однако некоторые компиляторы могут предоставлять доступ к инструкциям процессора с помощью встроенных функций . Кроме того, некоторые конструкции в стандартном коде ANSI C могут быть оптимизированы компилятором для инструкции языка ассемблера «rotate» на процессорах, которые имеют такую инструкцию. Большинство компиляторов C распознают следующую идиому и компилируют ее в одну 32-битную инструкцию rotate. [1] [2]
/* * Операции сдвига в C определены только для значений сдвига, которые * не отрицательны и меньше, чем sizeof(value) * CHAR_BIT. * Маска, используемая с побитовым И (&), предотвращает неопределенное поведение , * когда счетчик сдвига равен 0 или >= ширине беззнакового целого числа. */#include <stdint.h> // для uint32_t, чтобы получить 32-битные вращения, независимо от размера int. #include <limits.h> // для CHAR_BIT uint32_t rotl32 ( uint32_t значение , беззнаковое целое число count ) { const беззнаковое целое число mask = CHAR_BIT * sizeof ( значение ) - 1 ; count &= mask ; return ( значение << count ) | ( значение >> ( - count & mask )); } uint32_t rotr32 ( uint32_t значение , беззнаковое целое число count ) { const беззнаковое целое число mask = CHAR_BIT * sizeof ( значение ) - 1 ; count &= mask ; return ( значение >> count ) | ( значение << ( - count & mask )); }
Эта безопасная и удобная для компилятора реализация была разработана Джоном Регером [3] и доработана Питером Кордесом. [4] [5]
Часто встречается более простая версия, когда count
диапазон ограничен от 1 до 31 бита:
uint32_t rotl32 ( значение uint32_t , беззнаковое целое число ) { return ( значение << число ) | ( значение >> ( 32 - число )); }
Эта версия опасна, поскольку если равен count
0 или 32, она запрашивает 32-битный сдвиг, что является неопределенным поведением в стандарте языка C. Однако она, как правило, работает в любом случае, поскольку большинство микропроцессоров реализуют value >> 32
либо 32-битный сдвиг (производящий 0), либо 0-битный сдвиг (производящий исходный value
), и любой из них дает правильный результат в этом приложении.
Если бы последовательность бит 0001 0111 была подвергнута циклическому сдвигу на одну битовую позицию... (см. изображения ниже)
Если бы последовательность бит 1001 0110 была подвергнута следующим операциям:
Циклические коды — это разновидность блочного кода со свойством, что циклический сдвиг кодового слова всегда даст другое кодовое слово. Это мотивирует следующее общее определение: для строки s над алфавитом Σ пусть shift ( s ) обозначает множество циклических сдвигов s , а для множества строк L пусть shift ( L ) обозначает множество всех циклических сдвигов строк в L . Если L — циклический код, то shift ( L ) ⊆ L ; это необходимое условие для того, чтобы L был циклическим языком . Операция shift ( L ) изучалась в формальной теории языков . Например, если L — контекстно-свободный язык , то shift ( L ) снова контекстно-свободен. [6] [7] Кроме того, если L описывается регулярным выражением длины n , существует регулярное выражение длины O ( n 3 ), описывающее shift ( L ). [8]