Это не проблема с оператором ~
, который делает то, что должен, а с функцией bin
, которую вы используете для отображения результатов.
В Python, как и в большинстве компьютерных систем, отрицательные целые числа хранятся внутри в двоичном представлении «два дополнения». Это означает, что -1
представлен последовательностью всех 1
битов, и каждое нижнее целое число изменяет это значение с помощью нормальных правил вычитания целых чисел. Таким образом, -2
формируется путем вычитания 1
из -1
, и вы получаете набор из 1
битов, за которым следует ноль в качестве последнего бита.
Вот некоторые числа и двоичный код дополнения их двух 4-битные представления:
0 : 0000
1 : 0001
2 : 0010
5 : 0101
-1 : 1111 # this is ~0
-2 : 1110 # this is ~1
-3 : 1101 # this is ~2
-6 : 1010 # this is ~5
В отличие от многих других языков, целые числа Python не имеют заранее определенной длины в битах. Они не 16- или 32-битные, как целые числа short
и long
в C. Скорее они имеют динамический размер, с добавлением большего количества битов по мере необходимости для представления больших и больших чисел. Это вызывает сложную ситуацию, когда вам нужно представлять двоичные цифры в виде текста (как это делает функция bin
). Если вы знали, что ваш номер использует только 16 бит, вы могли бы каждый раз записывать 16-значную строку, но для динамически изменяемого числа необходимо другое решение.
И действительно, Python делает что-то другое в bin
функция. Положительные числа записываются с наименьшим количеством битов, необходимых для представления их значения. И отрицательные числа записываются не в дополнение к двум (как они фактически кодируются внутри), а вместо этого, ставя знак минус перед битовым представлением их абсолютного значения.
Таким образом, вы получаете Таблица, подобная этой, где побитовые дополнения не очевидны:
0 : 0b0
1 : 0b1
2 : 0b10
5 : 0b101
-1 : -0b1
-2 : -0b10
-3 : -0b11
-6 : -0b110
Что касается того, как получить двоичные представления для отрицательных чисел, подобных тем, которые указаны в первой таблице, единственный хороший способ - это выбрать некоторую степень двух это больше, чем любое из ваших чисел, и добавьте его ко всем отрицательным значениям перед форматированием:
MY_MAXINT = 2**4
for v in [0,1,2,5,-1,-2,-3,-6]:
if v < 0:
v += MY_MAXINT
print(format(v, '04b'))