何かが足りないのかもしれませんが、この単純なタスクを達成するための簡単な方法が見つかりません。「~」演算子を使用して 2 進数を否定すると、2 の補数により負の数が返されます。
>>> bin(~0b100010) # this won't return '0b011101'
'-0b100011'
従来の論理補数のように、0 を 1 に、またはその逆に切り替えたいだけの場合はどうでしょうか。
何かが足りないのかもしれませんが、この単純なタスクを達成するための簡単な方法が見つかりません。「~」演算子を使用して 2 進数を否定すると、2 の補数により負の数が返されます。
>>> bin(~0b100010) # this won't return '0b011101'
'-0b100011'
従来の論理補数のように、0 を 1 に、またはその逆に切り替えたいだけの場合はどうでしょうか。
>>> bin(0b111111 ^ 0b100010)
'0b11101'
>>>
関数としてのあなたの答え:
def complement(n):
size = len(format(n, 'b'))
comp = n ^ ((1 << size) - 1)
return '0b{0:0{1}b}'.format(comp, size)
>>> complement(0b100010)
'0b011101'
元のビット長を保持するようにしました。int コンストラクターは先行ゼロを気にしません。
>>> complement(0b1111111100000000)
'0b0000000011111111'
>> int(complement(0b1111111100000000), 2)
255
超厄介:
>>> '0b' + ''.join('10'[int(x)] for x in format(0b100010,'b')).lstrip('0')
'0b11101'
これは、私が出した数の補数を返す別の関数です。
ワンライナー:
def complement(c):
return c ^ int('1'*len(format(c, 'b')), 2)
より数学的な方法:
def complement(c):
n=0
for b in format(c, 'b'): n=n<<1|int(b)^1
return n
さらに、この最後のものを functools でワンライナー化します (そのようなバロック):
def complement(c):
return functools.reduce( lambda x,y: x<<1|y, [ int(b)^1 for b in format(c, 'b') ])
最後に、math.log を使用して 2 進数をカウントする最初のものの無駄にオタクっぽいバリアント:
def complement(c):
c ^ int('1' * math.floor(math.log((c|1)<<1, 2)), 2)