(-1 >> 1) == -1 - Почему? - PullRequest
       29

(-1 >> 1) == -1 - Почему?

7 голосов
/ 26 июня 2009

Почему (-1 >> 1) приводит к -1? Я работаю в Си, хотя я не думаю, что это должно иметь значение.

Не могу понять, чего мне не хватает ...

Вот пример программы на C, которая выполняет вычисления:

#include <stdio.h>



int main()
{
    int num1 = -1;

    int num2 = (num1 >> 1);

    printf( "num1=%d", num1 );

    printf( "\nnum2=%d", num2 );

    return 0;
}

Ответы [ 5 ]

23 голосов
/ 26 июня 2009

Поскольку целые числа со знаком представлены в дополнении до двух .

-1 будет 11111111 (если это было 8-битное число).

-1 >> 1 очевидно, знак распространяется так, что остается 11111111. Это поведение зависит от компилятора, но для Microsoft , когда сдвиг знака со знаком вправо (>>) копирует бит знака, в то время как сдвиг вправо без знака приводит к вставке 0 крайний левый бит.

11 голосов
/ 26 июня 2009

Арифметическое смещение вправо сохранит знак при смещении числа со знаком :

11111111 (-1) will stay 11111111 (-1) 

Напротив, Логическое смещение вправо не сохранит знак:

11111111 (-1) will become 01111111 (127)

Ваш код явно выполняет арифметическое смещение, поэтому бит знака ( MSB ) повторяется. То, что делает оператор (>>), зависит от деталей реализации платформы, которую вы используете. В большинстве случаев это арифметический сдвиг.

Также обратите внимание, что 11111111 может иметь два разных значения в зависимости от представления. Это также влияет на то, как они будут сдвинуты.

  • Если без знака, 11111111 представляет 255. Смещение вправо не сохранит знак, поскольку MSB не является знаковым битом.
  • Если подписано, 11111111 представляет -1. Арифметическое смещение вправо сохранит знак.
5 голосов
/ 26 июня 2009

Сдвиг битов отрицательного числа является поведением реализации в C. Результаты будут зависеть от вашей платформы и теоретически могут быть совершенно бессмысленными. Из стандарта C99 (6.5.7.5):

Результат E1 >> E2 - E1 сдвинутые вправо битовые позиции E2. Если Е1 имеет тип без знака или если E1 имеет тип со знаком и неотрицательное значение, значение результата является неотъемлемая часть отношения E1 / 2 ^ E2. Если E1 имеет подписанный тип и отрицательное значение, полученное значение реализация-де определено.

Причина, по которой это происходит, наиболее вероятна, поскольку ваш компилятор использует инструкцию x86 SAR (Shift Arithmetic Right) для реализации >>. Это означает, что произойдет расширение знака - наиболее значимый бит будет реплицирован в новый MSB, как только значение будет сдвинуто. Из руководств Intel :

Сдвиг арифметического вправо (SAR) и сдвигать логическое право (SHR) сдвинуть биты пункта назначения операнд вправо (к меньшему значительные битовые локации). Для каждого смещение, младший бит операнда назначения смещен в флаг CF, и наиболее значимый бит либо установлен, либо очищается в зависимости от инструкции тип. Инструкция SHR очищает самый значимый бит (см. рис. 7-8) в Intel® 64 и IA-32 Разработчики программного обеспечения для архитектуры Руководство, Том 1); инструкция SAR устанавливает или очищает наиболее значимые бит, соответствующий знаку (большинство значащий бит) от первоначального значения в операнде назначения. В действительности, инструкция SAR заполняет пустое смещенное значение положения бита с помощью знак несмещенного значения (см. Рисунок 7-9 в Intel® 64 и IA-32 Разработчики программного обеспечения для архитектуры Руководство, том 1).

3 голосов
/ 26 июня 2009

Когда вы сдвигаете вправо и самый левый бит равен 1, некоторые платформы / компиляторы будут вводить 0, а некоторые сохранят 1 и сделают новый самый левый бит равным 1. Это сохраняет знак числа, так что отрицательное число остается отрицательным и называется расширением знака.

Вы увидите разницу, если вы попробуете ((unsigned) -1) >> 1, который сделает беззнаковое смещение вправо и всегда будет сдвигаться в 0 бит.

1 голос
/ 26 июня 2009

расширение знака.

...