54

Python の整数は 2 の補数で格納されますよね?

それでも:

>>> x = 5
>>> bin(x)
0b101

と:

>>> x = -5
>>> bin(x)
-0b101

それはかなり不自由です。Python に REAL バイナリ ビットで数字を与え、その前に 0b を付けないようにするにはどうすればよいですか? そう:

>>> x = 5
>>> bin(x)
0101
>>> y = -5
>>> bin(y)
1011
4

15 に答える 15

90

マスクを提供すると最も効果的です。このようにして、符号拡張の範囲を指定します。

>>> bin(-27 & 0b1111111111111111)
'0b1111111111100101'

または、おそらくもっと一般的に:

def bindigits(n, bits):
    s = bin(n & int("1"*bits, 2))[2:]
    return ("{0:0>%s}" % (bits)).format(s)

>>> print bindigits(-31337, 24)
111111111000010110010111

基本的な理論では、数値の実際の幅はストレージのサイズの関数です。32ビットの数値の場合、負の数は32のセットのMSBに1が含まれます。64ビットの値の場合、64ビットが表示されます。

ただし、Pythonでは、整数の精度はハードウェアの制約にのみ制限されます。私のコンピューターでは、これは実際には機能しますが、 xの値を格納するためだけに9GBのRAMを消費します。それより高いと、MemoryErrorが発生します。RAMが多ければ、もっと多くの数を保存できます。

>>> x = 1 << (1 << 36)

それを念頭に置いて、2進数は何を表してい-1ますか?前の例が示すように、Pythonは文字通り数百万(さらには数十億)ビットの精度を十分に解釈できます。2の補数では、符号ビットは左端まで拡張されますが、Pythonでは事前定義されたビット数はありません。必要な数だけあります。

しかし、その後、あいまいさに遭遇します。バイナリは、1を表しますか1、それとも-1?まあ、それはどちらかかもしれません。111を表します7か?-1繰り返しますが、どちらかである可能性があります。精度に応じて、両方を表し111111111ます。511-1

Pythonには、これらの数値を2進数で表現して、それらの意味があいまいにならないようにする方法が必要です。0bプレフィックスは「この番号は2進数です」とだけ言っています。「この数字0xは16進数です」という意味です。それで、私が言う0b1111場合、ユーザーが-1または15を望んでいるかどうかをどうやって知ることができますか?2つのオプションがあります。

オプションA: 符号ビット
すべての数値が符号付きであると宣言できます。左端のビットは符号ビットです。つまり0b1、は-1であり、は1です。これは、も-1であり、は7で0b01あることを意味します。結局、これは、特にほとんどの2進演算がとにかく符号なしになり、人々がより多くなるため、役立つよりもおそらく混乱します。明示的な符号ビットが含まれていなかったために、誤って数値を負としてマークすることにより、間違いに遭遇する可能性があります。0b1110b0111

オプションB: 符号表示
このオプションを使用すると、2進数は符号なしで表され、負の数には10進数と同じように「-」プレフィックスが付きます。これは、(a)10進数との整合性が高く、(b)2進値が使用される可能性が最も高い方法との互換性が高くなります。2の補数表現を使用して負の数を指定することはできなくなりますが、2の補数はストレージ実装の詳細であり、基になる値自体を適切に示すものではないことに注意してください。ユーザーが理解しなければならないものである必要はありません。

結局、オプションBが最も理にかなっています。混乱が少なく、ユーザーはストレージの詳細を理解する必要がありません。

于 2012-10-18T02:31:11.940 に答える
16

バイナリ シーケンスを 2 の補数として正しく解釈するには、シーケンスに関連付けられた長さが必要です。CPU レジスタに直接対応する低レベルの型を操作している場合、暗黙的な長さがあります。Python の整数は任意の長さを持つことができるため、実際には内部の 2 の補数形式はありません。数値には長さが関連付けられていないため、正の数値と負の数値を区別する方法はありません。あいまいさを取り除くために、bin() は、負の数値をフォーマットするときにマイナス記号を含めます。

Python の任意長の整数型は、実際には符号と大きさの内部形式を使用します。論理演算 (ビット シフト、and、or など) は、2 の補数形式を模倣するように設計されています。これは、多精度ライブラリの典型です。

于 2012-10-18T04:53:39.790 に答える
3

標準ライブラリを使用して必要なものを取得する方法がわかりません。変換を行うスクリプトとパッケージがいくつかあります。

私はただ「なぜ」、そしてなぜそれが不完全ではないのかを書き留めたかったのです。

bin()はバイナリビットを返しません。数値を2進文字列に変換します。先頭の「0b」は、Python言語の定義に従って、2進数を処理していることをインタプリタに通知します。このようにして、次のように2進数を直接操作できます。

>>> 0b01
1
>>> 0b10
2
>>> 0b11
3
>>> 0b01 + 0b10
3

それはラメではありません。それは素晴らしいことです。


http://docs.python.org/library/functions.html#bin

bin(x)

整数を2進文字列に変換します。

http://docs.python.org/reference/lexical_analysis.html#integers

整数および長整数リテラルは、次の字句定義によって記述されます。

bininteger :: = "0"( "b" | "B")bindigit +

bindigit :: = "0" | 「1」

于 2012-10-18T02:34:57.783 に答える
3
tobin = lambda x, count=8: "".join(map(lambda y:str((x>>y)&1), range(count-1, -1, -1)))

例えば

tobin(5)      # =>  '00000101'
tobin(5, 4)   # =>      '0101'
tobin(-5, 4)  # =>      '1011'

または明確な関数として:

# Returns bit y of x (10 base).  i.e. 
# bit 2 of 5 is 1
# bit 1 of 5 is 0
# bit 0 of 5 is 1
def getBit(y, x):
    return str((x>>y)&1)

# Returns the first `count` bits of base 10 integer `x`
def tobin(x, count=8):
    shift = range(count-1, -1, -1)
    bits = map(lambda y: getBit(y, x), shift)
    return "".join(bits)

( WJ Van de Laan のコメントから改作)

于 2013-03-24T09:13:27.960 に答える
2
def tobin(data, width):
    data_str = bin(data & (2**width-1))[2:].zfill(width)
    return data_str
于 2013-04-18T04:06:53.543 に答える
2

あなたが最終的に何をしたいのかは完全にはわかりませんが、bitarrayパッケージを確認することをお勧めします。

于 2012-10-18T02:20:33.330 に答える
2

スライスを使用して、不要な「0b」を取り除きます。

bin(5)[2:] '101'

または数字が必要な場合は、

tuple ( bin(5)[2:] ) ('1'、'0'、'1')

あるいは

map( int, tuple( bin(5)[2:] ) ) [1, 0, 1]

于 2014-01-10T09:27:30.040 に答える
1

正の数の場合は、次を使用します。

bin(x)[2:].zfill(4)

負の数の場合、少し異なります。

bin((eval("0b"+str(int(bin(x)[3:].zfill(4).replace("0","2").replace("1","0").replace("2","1"))))+eval("0b1")))[2:].zfill(4)

スクリプト全体として、次のようになります。

def binary(number):
    if number < 0:
        return bin((eval("0b"+str(int(bin(number)[3:].zfill(4).replace("0","2").replace("1","0").replace("2","1"))))+eval("0b1")))[2:].zfill(4)
    return bin(number)[2:].zfill(4)      
x=input()
print binary(x)
于 2012-10-18T02:31:38.370 に答える
1

正の数と負の数の符号拡張を提供する tylerl の非常に役立つ回答の変更 (エラー チェックなし)。

def to2sCompStr(num, bitWidth):
    num &= (2 << bitWidth-1)-1 # mask
    formatStr = '{:0'+str(bitWidth)+'b}'
    ret =  formatStr.format(int(num))
    return ret

例:

In [11]: to2sCompStr(-24, 18)
Out[11]: '111111111111101000'

In [12]: to2sCompStr(24, 18)
Out[12]: '000000000000011000'
于 2015-04-02T07:14:05.273 に答える
0

ビット単位の XOR のプロパティを利用できます。ビット単位の XOR を使用してビットを反転し、1 を追加します。次に、Python の組み込みの bin() 関数を使用して、2 の補数のバイナリ表現を取得できます。関数の例を次に示します。

def twos_complement(input_number):
    print(bin(input_number))                            # prints binary value of input
    mask = 2**(1 + len(bin(input_number)[2:])) - 1      # Calculate mask to do bitwise XOR operation
    twos_comp = (input_number ^ mask) + 1               # calculate 2's complement, for negative of input_number (-1 * input_number)
    print(bin(twos_comp))                               # print 2's complement representation of negative of input_number.   
于 2021-02-05T02:51:36.057 に答える