как целые числа со знаком представлены в двоичном формате
Первоначально размещено на 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
и 1
results -128
. Странно, нет?
Еще один вывод, который можно сделать, касается зеркального отображения. Если бы вы могли сложить общую длину целых чисел посередине, у вас было бы:
- 0 зеркальное отображение -1;
- 1 зеркальное отображение -2;
- 2 зеркалирование -3 и так далее, пока;
- (2ˆ31−1) зеркальное отображение - (2ˆ31);
- (X − 1) зеркальное отображение −X.
Любопытство: обратите внимание, что индивидуальная сумма всех отраженных значений равна -1.
Источники
Учебники по Java - примитивный тип данных
Учебное пособие - тип данных C