Почему при сдвиге -1 на 1 бит мы получаем -1

Почему при сдвиге -1 на 1 бит мы получаем -1, если первый бит, который отвечает за знак сдвигается и по идее должно быть положительное число

std::cout << (-1 >> 1);

Ответы (4 шт):

Автор решения: LShadow77

В архитектурах x86/amd64 существует два вида сдвига вправо: бесзнаковый и знаковый. В первом случае старшие биты после сдвига заполняются нулями. Во втором - знаковыми разрядами, т.е. нулями для положительных чисел и единицами для отрицательных (у всех отрицательных знаковых целых старший бит равен 1).

Какой вид сдвига применяется для оператора >> в C++? Тут всё очень просто: для бесзнаковых целых (unsigned int) - это бесзнаковый сдвиг, для целых со знаком (int), соответственно, - знаковый.

Из-за особенности машинного представления отрицательных целых в x86/amd64, у числа -1 все биты равны единице. Следовательно, после знакового сдвига вправо старшие биты устанавливаются в единицу, и как результат, все биты получившегося числа остаются равными единице, т.е. получается всё та же -1.

P.S. Рекомендую почитать про представление целых чисел в т.н. дополнительном коде.

P.P.S. Ещё один занимательный факт: если у числа -2147483648 (тип int) поменять знак, то получится то же самое число -2147483648.

→ Ссылка
Автор решения: ampawd

Биты отрицательных чисел перевернуты, поэтому при сдвиге вправо 0 становятся 1. А знаковый бит который 1 так и так не будет менятся. В случае с -1 все биты 1 так что тут кроме -1 при сдвиге вправо -1 на 1 ничего другого и быть не может.

Но результат, вобще говоря от реализации зависит. Хотя стоит отметить, что в основном все реализации делают именно такой сдвиг.

→ Ссылка
Автор решения: Harry

... ибо сказано в стандарте c++20 :) —

The value of E1 >> E2 is E1/2^E2, rounded down. [Note: E1 is right-shifted E2 bit positions. Right-shift on signed integral types is an arithmetic right shift, which performs sign-extension. —end note]

Впрочем, еще в стандарте c++17 было сказано иное:

The value of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a non-negative value, the value of the result is the integral part of the quotient of E1/2^E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined.

Но в целом стандарт C++20 просто узаконил сложившуюся практику.

→ Ссылка
Автор решения: Герман Борисов

В дополнительном коде число -1 хранится как число со всеми установленными битами.

Для байта это 11111111b, для слова 1111111111111111b, для 4-байтного целого 11111111111111111111111111111111b и так далее.

Для одного байта: если мы сдвинем 11111111b вправо на один бит мы получим x1111111b, и старший бит нужно заполнить или 0 или 1. Если мы подставит 0, то получим 01111111b, что равно 127, то есть максимально положительно знаковое значение данной длины. Если подставим 1 - получим опять 11111111b, то есть -1.

Для двух байтов соответственно мы получим или -1 или 32767. Для четырёх - -1 или 2147483647.

Авторы языка решили, что получить -1 будет более логично.

→ Ссылка