Питер дал вам толкование кода, основанного на том, что вы стоите вокруг. Вот еще один, более побитовый, один:
Последовательные сдвиги в этом коде «заполняются» с 1-м позицией всех бит ниже самой высокой, установленной в начале. Давайте посмотрим на это более подробно:
Пусть x=0b0001 ???? ???? ????
бинарное представление 16 битного числа, где ?
может быть 0 или 1.
x |= x >> 1; // x = 0b0001 ???? ???? ???? | 0b0000 1??? ???? ???? = 0b0001 1??? ???? ????
x |= x >> 2; // x = 0b0001 1??? ???? ???? | 0b0000 011? ???? ???? = 0b0001 111? ???? ????
x |= x >> 4; // x = 0b0001 111? ???? ???? | 0b0000 0001 111? ???? = 0b0001 1111 111? ????
x |= x >> 8; // x = 0b0001 1111 111? ???? | 0b0000 0000 0001 1111 = 0b0001 1111 1111 1111
Следовательно, сдвиги дают вам номер из форма 0b00...011...1
, то есть только 0 с, то только 1 с, что означает номер формы 2^n-1
. Вот почему вы добавляете 1
в конце, чтобы получить мощность 2. Чтобы получить правильный результат, вам также необходимо удалить 1
с самого начала, чтобы компенсировать тот, который вы добавите в конце.
Теперь для отрицательных чисел стандарт C++ не определяет, какие наиболее значимые биты должны быть при правом смещении. Но являются ли они 1
или 0
не имеет значения в данном конкретном случае, до тех пор, как ваше представление отрицательных чисел используется в его наиболее значимых битовых позициях в 1
, то есть почти все из них. *
потому что вы всегда or
х с сам, все эти самые левые биты (где сдвиги отличаются) будут or
ed с 1
s.В конце алгоритма вы вернетесь 0b11111...1 + 1
, который в вашем случае означает 0
(потому что вы используете дополнение 2s, результатом будет 1
в дополнении 1s и -2 количество бит - 1 + 1 в знаке-величине).
* Это справедливо для представлений основных отрицательных чисел, от большинства до наименее популярных: то есть дополнения 2s, знака-величины и дополнения 1s. Примером, где это не так, является избыточное представление K, которое используется для индексов с плавающей запятой IEEE.
Побитовые операции на самом деле не предназначены для работы с отрицательными числами. Вы понимаете, как работает код для неотрицательных чисел? – SergeyA
int - целое число со знаком. – OldProgrammer
@SergeyA Я понимаю, как код работает для не отрицательного числа, но я не понимаю, почему это не будет работать с отрицательным числом. –