Правильные отрицательные числа смещения в C

Я любил "кучу" ответа Cody, таким образом, вот мой подобный вклад в C++:

template <int i>
class Overflow {
    typedef typename Overflow<i + 1>::type type;
};

typedef Overflow<0>::type Kaboom;

Не запись гольфа кода каким-либо образом, но тем не менее, что-либо для meta переполнения стека!:-P

26
задан Peter Mortensen 8 August 2015 в 23:17
поделиться

6 ответов

Похоже, ваша реализация, вероятно, выполняет арифметический битовый сдвиг с двумя дополнительными числами. В этой системе он сдвигает все биты вправо, а затем заполняет верхние биты копией того, что было последним битом. Итак, для вашего примера, обработка int как 32-битного здесь:

nPosVal = 00000000000000001111111111111111
nNegVal = 11111111111111110000000000000001

После сдвига у вас есть:

nPosVal = 00000000000000000111111111111111
nNegVal = 11111111111111111000000000000000

Если вы конвертируете это обратно в десятичное, вы получите 32767 и -32768 соответственно.

Фактически, сдвиг вправо вращается в сторону отрицательной бесконечности.

Редактировать: Согласно разделу 6.5.7 последнего проекта стандарта , такое поведение при отрицательных числах зависит от реализации:

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

Их заявленное рациональное для этого:

Комитет C89 подтвердил свободу в реализации, предоставленную K&R в не требуя, чтобы подписанная операция сдвига вправо была расширена, поскольку такое требование может замедлить быстрый код и поскольку полезность расширенных сдвигов знаков незначительна. (Сдвиг отрицательного дополнения до двух целое число, арифметически правильное одно место не то же самое, что деление на два!)

Так что это теоретически зависит от реализации. На практике я никогда не встречал реализации , не выполняющей арифметический сдвиг вправо, когда левый операнд подписан.

40
ответ дан 28 November 2019 в 06:24
поделиться

Нет, при работе с целыми числами дробные числа вроде 0,5 не получаются. Результаты можно легко объяснить, если посмотреть на двоичное представление двух чисел:

      65535: 00000000000000001111111111111111
     -65535: 11111111111111110000000000000001

Битовый сдвиг на один бит вправо и расширение влево (обратите внимание, что это зависит от реализации, спасибо Тренту):

 65535 >> 1: 00000000000000000111111111111111
-65535 >> 1: 11111111111111111000000000000000

Convert назад к десятичному виду:

 65535 >> 1 = 32767
-65535 >> 1 = -32768
18
ответ дан 28 November 2019 в 06:24
поделиться

Спецификация C не определяет, сдвигается ли знаковый бит или нет. Это зависит от реализации.

7
ответ дан 28 November 2019 в 06:24
поделиться

При сдвиге вправо младший бит отбрасывается.

0xFFFF = 0 1111 1111 1111 1111, сдвиг вправо дает 0 0111 1111 1111 1111 = 0x7FFF

-0xFFFF = 1 0000 0000 0000 0001 (дополнение до 2), что сдвигается вправо на 1 1000 0000 0000 0000 = -0x8000

3
ответ дан 28 November 2019 в 06:24
поделиться

A-1: ​​Да. 0xffff >> 1 - это 0x7fff или 32767. Я не уверен, что делает -0xffff. Это странно.

A-2: Сдвиг - это не то же самое, что разделение. Это битовый сдвиг - примитивная двоичная операция. То, что его иногда можно использовать для некоторых типов разделения, удобно, но не всегда одинаково.

3
ответ дан 28 November 2019 в 06:24
поделиться

Ниже уровня C машины имеют ядро ​​ЦП, которое полностью целое или скалярное . Хотя в наши дни каждый настольный процессор имеет FPU, это было не всегда так, и даже сегодня встроенные системы создаются без инструкций с плавающей запятой.

Сегодняшние парадигмы программирования, конструкции и языки ЦП восходят к эпохе, когда FPU даже не могли

Итак, инструкции ЦП реализуют операции с фиксированной точкой , обычно рассматриваемые как чисто целочисленные операции. Только если программа объявляет элементы float или double , будут существовать какие-либо дроби. (Что ж, вы можете использовать операции ЦП для «фиксированной точки» с дробями, но это сейчас и всегда было довольно редко.)

Независимо от того, что требовал комитет по стандартизации языка много лет назад, все разумные машины передают знаковый бит при сдвиге вправо чисел со знаком. Сдвиги вправо беззнаковых значений сдвигаются на нули слева. Сдвинутые справа биты падают на пол.

Для дальнейшего понимания вам нужно будет исследовать «арифметику с дополнением до двух».

2
ответ дан 28 November 2019 в 06:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: