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

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

это представление дополнения two или с помощью MSB (самый значительный бит)?

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

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

4 ответов


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

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

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

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

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

number | two's 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-битного int, а бит знака Нижнего короткого игнорируется при использовании в этом 32-битном int. Затем, как 32-битный подписанный int, есть бит заполнения (в середине 32 бит), который игнорируется при определении значения 32-разрядный подписанный int. Но если этот 32-разрядный элемент рассматривается как 32-разрядный unsigned int, то этот бит заполнения виден программе пользователя. Комитету C сказали, что есть машина, которая работает таким образом, и это одна из причин того, что биты заполнения были добавлены в C99.

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

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

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


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

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

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

одна полезная особенность дополнения two заключается в том, что 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)

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


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