как целые числа со знаком представлены в двоичном формате

Первоначально размещено на https://www.wandercosta.com/twos-complement/

Вы когда-нибудь задумывались о том, как числа представлены на вашем компьютере? Все мы знаем, что компьютеры «разговаривают» в двоичном формате, но как именно это работает?

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

В следующих примерах для объяснения я буду использовать типы данных Java 7. Java 8 SE предоставляет некоторые отличия в int типах, которые не будут рассматриваться.

Пределы

Структуры данных должны иметь ограничения. И это не только старое требование, учитывая ограничения старого компьютера. В настоящее время, когда объем данных вводится с помощью BigData и многих других сценариев использования большого объема данных, разумно думать о представлении для достижения хорошей производительности и возможностей.

Это одна из основных причин существования разных типов данных. Даже при нынешних технологиях и возможностях компьютеров ресурсы по-прежнему не безграничны. Очень часто существуют ограничения в представлении, что означает, что вы должны выбрать соответствующий тип данных в соответствии с решаемой проблемой.

В Java, например, примитивный тип:

  • byte подписан, длина 8 бит (от - (2ˆ8) до (2ˆ8−1));
  • short подписан, длина 16 бит (от - (2ˆ16) до (2ˆ16−1));
  • int подписан, длина 32 бита (от - (2ˆ32) до (2ˆ32−1));
  • long подписан, длина 64 бита (от - (2ˆ64) до (2ˆ64−1)).

C, однако, имеет как подписанную, так и беззнаковую версию вышеупомянутых примитивных типов, а его длина long составляет 32 бита.

Понимание представления

По умолчанию целые числа int имеют длину 32 бита со знаком и представлены в виде дополнения до двух, что означает, что оно имеет следующие ограничения:

  • 0000 0000 0000 0000 0000 0000 0000 0000 представляет 0;
  • 0111 1111 1111 1111 1111 1111 1111 1111 представляет 2,147,483,647 (2ˆ31-1);
  • 1000 0000 0000 0000 0000 0000 0000 0000 представляет _13 _ (- (2ˆ32));
  • 1111 1111 1111 1111 1111 1111 1111 1111 представляет -1.

Все остальные три примитива, использующие два дополнения, работают аналогично.

Например, значение 45 может быть представлено любым из упомянутых типов. Однако в фоновом режиме память, выделенная для каждого типа данных, будет значительно отличаться, поскольку в ней будут храниться:

  • 0010 1101, если тип данных byte;
  • 0000 0000 0010 1101, если тип данных short;
  • 0000 0000 0000 0000 0000 0000 0010 1101, если тип данных int;
  • 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0010 1101, если тип данных long;

Выводы

Самый левый бит (самый старший бит) определяет сигнал. То есть он определяет, является ли число положительным (0) или отрицательным (1).

С учетом int переменных получается двоичная сумма 2,147,483,647 и 1 -2,147,483,648. Учитывая byte переменных, двоичную сумму 127 и 1results -128. Странно, нет?

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

  • 0 зеркальное отображение -1;
  • 1 зеркальное отображение -2;
  • 2 зеркалирование -3 и так далее, пока;
  • (2ˆ31−1) зеркальное отображение - (2ˆ31);
  • (X − 1) зеркальное отображение −X.

Любопытство: обратите внимание, что индивидуальная сумма всех отраженных значений равна -1.

Источники

Учебники по Java - примитивный тип данных
Учебное пособие - тип данных C