web-dev-qa-db-ja.com

ビット単位の演算単項〜(反転)

~演算子に少し混乱しています。コードは以下のとおりです。

a = 1
~a  #-2
b = 15
~b  #-16

~はどのように機能しますか?

~aは次のようになると思いました。

0001 = a
1110 = ~a 

何故なの?

51
Alcott

あなたはまったく正しいです。 2の補数 整数表現のアーティファクトです。

16ビットでは、1は0000 0000 0000 0001として表されます。反転すると、1111 1111 1111 1110、つまり-2が得られます。同様に、15は0000 0000 0000 1111です。反転すると、1111 1111 1111 0000、つまり-16が得られます。

一般的に、~n = -n - 1

49

「〜」演算子は、「xのビット単位の反転は x + 1)として定義されます。整数にのみ適用されます。」---(Python Doc-5.5

この文の重要な部分は、これが「整数」(整数とも呼ばれる)に関連していることです。あなたの例は4ビットの数値を表しています。

'0001' = 1 

4ビット数の整数範囲は「-8..0..7」です。一方、負の数を含まない「符号なし整数」を使用でき、4ビット数の範囲は「0..15」になります。

Pythonは整数で動作するため、説明した動作が期待されます。整数は2の補数を使用して表されます。4ビット数の場合、次のようになります。

 7 = '0111'
 0 = '0000'
-1 = '1111'
-8 = '1000'

Pythonは、32ビットOSの場合、整数表現に32ビットを使用します。以下を使用して最大の整数を確認できます。

sys.maxint # (2^31)-1 for my system

符号なし整数が返されるようにするには、4ビットの数値をマスクする必要があります。

'0001' = a   # unsigned '1' / integer '1'
'1110' = ~a  # unsigned '14' / integer -2

(~a & 0xF) # returns 14

代わりに、符号なしの8ビットの数値範囲(0..255)を取得したい場合は、次を使用します。

(~a & 0xFF) # returns 254
29
sebs

私が望んでいることをするより簡単な解決策を見つけたようです:

uint8: x ^ 0xFF
uint16: x ^ 0xFFFF
uint32: x ^ 0xFFFFFFFF
uint64: x ^ 0xFFFFFFFFFFFFFFFF
6
user1919695

また、(たとえばnumpyパッケージからの)署名されていないintを使用して、予想される動作を実現することもできます。

>>> import numpy as np
>>> bin( ~ np.uint8(1))
'0b11111110'
3
user1747134

Pythonの単項反転演算子〜x =x + 1)、およびこれisは、メモリ内の各ビットを反転するのと同じです。

例えば

>>> 0b110    # an integer defined with a binary literal
# 0|1,1,0    = in sign|magnitude form
# +|4,2,0    = each bit's contribution to the int
# +1*(4+2+0) =>
6            

>>> bin(~0b110) # get the binary representation of inverted 0b110
# 1|001         = each bit simply inverted (invert sign bit too)
# -|4+2+0 +1    = each bit's contribution to the int, ‡See note
# -1*(4+2+0+1)  = -7    (the answer we want that represents each bit flipped)
# -0b111        = binary representation of -7
-0b111          = it resembles 1|111 but it in memory it is actually 1|001

---(-0b111is1|001メモリ内。正の2進数とは異なり、-ve 2進数表現をメモリに格納されているものとして解釈しないでください。

‡注:バイナリの負の数は逆方向にカウントされるため、各-veビット位置は、0の場合、intの構成にのみカウントされ、追加する必要があります- 1から最終結果まで:

# in-memory  = int  (displayed as)
1|11..111    = -1   (-0b1)
1|11..110    = -2   (-0b10)
1|11..101    = -3   (-0b11)
1|11..100    = -4   (-0b100)
# and so on...
0
Riaz Rizvi