Представление отрицательных чисел в C?

Как C представляет отрицательные целые числа?

Является ли это двумя дополнениями или с использованием MSB (самый старший бит)?

-1 в шестнадцатеричном формате ffffffff.

Поэтому, пожалуйста, проясните это для меня.

Ответ 1

ISO C (C99 section 6.2.6.2/2 в этом случае, но он переносит на более поздние итерации стандарта (a)), заявляет, что реализация должна выбрать одно из трех разных представлений для целочисленных типов данных, два дополнения, одно дополнение или знак/величина (хотя невероятно вероятно, что две реализации дополнения намного перевешивают другие).

Во всех этих представлениях положительные числа идентичны, единственная разница заключается в отрицательных числах.

Чтобы получить отрицательное представление для положительного числа, вы:

  • инвертировать все биты, а затем добавить один на два дополнения.
  • инвертировать все биты для дополнения.
  • инвертировать только бит знака для знака/величины.

Вы можете увидеть это в таблице ниже:

number | two complement    | ones' complement    | sign/magnitude
=======|=====================|=====================|====================
     5 | 0000 0000 0000 0101 | 0000 0000 0000 0101 | 0000 0000 0000 0101
    -5 | 1111 1111 1111 1011 | 1111 1111 1111 1010 | 1000 0000 0000 0101

Имейте в виду, что ISO не требует, чтобы все биты использовались в представлении. Они вводят понятие знакового бита, битов значения и битов заполнения. Сейчас я никогда не видел реализацию с битами заполнения, но из документа с обоснованием C99 у них есть такое объяснение:

Предположим, что машина использует пару 16-битных шорт (каждая со своим собственным знаковым битом) для создания 32-битного целого числа, а знаковый бит младшего шорта игнорируется при использовании в этом 32-битном целом. Затем, как 32-разрядный со знаком int, есть бит заполнения (в середине 32-битного), который игнорируется при определении значения 32-разрядного со знаком int. Но если этот 32-битный элемент обрабатывается как 32-битное беззнаковое целое, то этот бит дополнения виден программе пользователя. Комитету C сказали, что есть машина, которая работает таким образом, и это одна из причин, по которой биты заполнения были добавлены в C99.

Я полагаю, что машиной, о которой они, возможно, имели в виду, был Datacraft 6024 (и его наследники из Harris Corp). В этих машинах у вас было 24-битное слово, используемое для целого числа со знаком, но, если вы хотели получить более широкий тип, два из них были объединены в 47-битное значение, а бит знака одного из слов игнорировался:

+---------+-----------+--------+-----------+
| sign(1) | value(23) | pad(1) | value(23) |
+---------+-----------+--------+-----------+
\____________________/ \___________________/
      upper word            lower word

(a) Интересно, что, учитывая нехватку современных реализаций, которые фактически используют два других метода, был толчок к тому, чтобы два дополнения были приняты как один истинный метод. В стандарте C++ этот процесс прошел довольно долгий путь (WG21 является рабочей группой, ответственной за это) и теперь, по-видимому, рассматривается также и для C (WG14).

Ответ 2

C допускает знак/величину, одно дополнение и два представления комплементарных целых чисел. Наиболее типичное аппаратное обеспечение использует два дополнения для целых чисел и знак/значение для плавающей запятой (и еще одна возможность - представление "смещения" для показателя с плавающей запятой).

Ответ 3

-1 в шестнадцатеричном формате - ffffffff. Поэтому, пожалуйста, уточните меня в этом отношении.

В двух дополнениях (безусловно, наиболее часто используемом представлении) каждый бит, кроме самого значимого бита (MSB), справа налево (увеличение порядка величины) имеет значение 2 n где n возрастает с нуля на единицу. MSB имеет значение -2 n.

Так, например, в 8 бит целочисленном двоичном дополнении, MSB имеет значение места -2 7 (-128), поэтому двоичное число: 1111 1111 2 равна -128 + 0111 1111 2= -128 + 127 = -1

Одна полезная особенность двух дополнений состоит в том, что процессор ALU требует только блока сумматора для вычитания, путем формирования двух дополнений правого операнда. Например, 10-6 эквивалентно 10 + (-6); в 8-битном двоичном (для простоты объяснения) это выглядит так:

   0000 1010
  +1111 1010
   ---------
[1]0000 0100  = 4 (decimal)

Где [1] - отброшенный бит переноса. Другой пример; 10 - 11 == 10 + (-11):

   0000 1010
  +1111 0101
   ---------
   1111 1111  = -1 (decimal)

Еще одна особенность двух дополнений состоит в том, что она имеет единственное значение, представляющее ноль, тогда как знак-величина и одно дополнение каждая имеют два; +0 и -0.

Ответ 4

Для интегральных типов это обычно два дополнения (специфические для реализации). Для с плавающей запятой есть знаковый бит.