Here are some caveats in printing complements(1s and 2s) in binary form, in python:
UNSIGNED RANGE: 0 to (2^k)-1 for k bit number
ex: 0 to (2^32)-1 numbers
ex: 0 to 7 for 3 bit unsigned numbers (count = 8)
SIGNED RANGE: -2^(k-1) to +2^(k-1)-1 for 1+k bit number (k-1 is for dividing current range k into two equal half)
ex: -2^31 to +(2^31)-1 numbers
ex -8 to +7 for 1+3 bit signed numbers (count = 8)
bin(int)->str converts an integer to binary string
CAVEAT: 1. Since in python there is no limit to length of integer
for ~x or !x (1s_complement/not/negate) we can't determine how many bits after MSB needs to be 1
so python just prints out unsigned value of target negative number in binary format with a
'-' sign in the beginning
ex: for x = b'01010'(10) we get ~x = -0b'1011' (-11)
but we should be getting -16+5 = -11
(-b'10000'+b'00101') = -b'10101' (-11 signed) or (21 unsigned)
to get real binary value after negation(or 1s complement) one could simulate it
NOTE: 2^0 is always 1, so (2**0 == 1) in python
NOTE: (1 << k) is always 2^k (left shift is 2 raised to the power k)
ex: bin((1 << k)-1 - x) which is ((2^k)-1)-x (1s complement)
ex: bin((1 << k)-1 - x) + 1 which is (2^k)-x (2s complement)
2. Same goes for reverse parsing of signed binary string to int:
ex: int("-0b'0101'", 2) gives -5 but instead it actually is -11 assuming -0b represents all bits
from MSB till current to be like 1111......0101 which is actually -16+5 = -11
BUT due to PYTHON's limitation of representing signed binary values we need to adhere to
current way of parsing considering unsigned binary strings with sign in front for -ve numbers
# NOTE: how the significant prefix zeros doesn't matter in both +ve and -ve cases
# Byte type inputs
x = b'+1010' # valid +ve number byte string
x = b'1010' # valid +ve number byte string
x = b'-1010' # valid -ve number byte string
x = b'+01010' # valid +ve number byte string
x = b'01010' # valid +ve number byte string
x = b'-01010' # valid -ve number byte string
int(b'101') # interprets as base 10 for each digit
int(b'101', 2) # interprets as base 2 for each digit
int(b'101', 8) # interprets as base 8 for each digit
int(b'101', 10) # interprets as base 10 for each digit
int(b'101', 16) # interprets as base 16 for each digit
# String type inputs
x = '+1010' # valid +ve number string
x = '1010' # valid +ve number string
x = '-1010' # valid -ve number string
x = '+01010' # valid +ve number string
x = '01010' # valid +ve number string
x = '-01010' # valid -ve number string
int('101') # interprets as base 10 for each digit
int('101', 2) # interprets as base 2 for each digit
int('101', 8) # interprets as base 8 for each digit
int('101', 10) # interprets as base 10 for each digit
int('101', 16) # interprets as base 16 for each digit
# print(bin(int(x, 2)), int(x,2), ~int(x, 2), bin(~int(x,2)), "-"+bin((1<<k)-1 - int(x,2)))
k = 5 # no of bits
assert 2**0 == 1 # (2^0 is always 1)
_2k = (1 << k) # (2^k == left shift (2^0 or 1) by k times == multiply 2 by k times)
x = '01010' # valid +ve number string
x = int(x,2)
print("input:", x) # supposed to be 1s complement of binStr but due to python's limitation,
# we consider it -(unsigned binStr)
_1s = '-'+bin((_2k-1)-x)
print("1s complement(negate/not): ", _1s, ~x)
_2s = '-'+bin(_2k-x)
print("2s complement(1s +1): ", _2s, ~x+1)
output:
k = 5 (5 bit representation)
input: 10
1s complement(negate/not): -0b10101 -11
2s complement(1s +1): -0b10110 -10
k=32 (32 bit representation)
input: 10
1s complement(negate/not): -0b11111111111111111111111111110101 -11
2s complement(1s +1): -0b11111111111111111111111111110110 -10