web-dev-qa-db-ja.com

Pythonの2の補数バイナリ?

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
35
Thor Correia

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

「なぜ」と、なぜそれがラメでないのかを書きたかっただけです。

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

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

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


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

bin(x)

整数をバイナリ文字列に変換します。

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

整数および長整数リテラルは、次の字句定義で説明されています。

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

bindigit :: = "0" | 「1」

3

マスクを提供すると最適に機能します。そのようにして、署名する範囲を指定します。

>>> 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では、整数精度はハードウェアの制約のみに制限されます。私のコンピューターでは、これは実際に動作しますが、9GBのRAMを保存するだけでx。それより高いものはありますが、MemoryErrorが発生します。

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

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

しかし、その後、あいまいさが発生します。バイナリ11または-1を表しますか?まあ、どちらかかもしれません。 1117または-1を表しますか?繰り返しますが、それはどちらかです。 111111111511、または-1...を表します。両方とも、精度に応じて異なります。

Pythonには、これらの数値をバイナリで表現する方法が必要であるため、それらの意味のあいまいさはありません。 0bプレフィックスは、「この数値はバイナリです」とだけ言っています。 0xと同じように、「この数値は16進数です」という意味です。 0b1111と言うと、ユーザーが-1または15を望んでいるかどうかをどのように知ることができますか?次の2つのオプションがあります。

オプションA:符号ビット
すべての数字に署名があり、左端のビットが符号ビットであることを宣言できます。つまり、0b1は-1で、0b01は1であるということです。つまり、0b111も-1ですが、0b0111は7です。 ほとんどのバイナリ算術はとにかく符号なしになりますであり、明示的な符号ビットが含まれていないため、誤って数字を負としてマークすることで人々がミスに陥りやすいため、特に役立つよりも混乱します。

オプションB:記号の表示
このオプションを使用すると、2進数は符号なしで表され、負数には10進数と同様に「-」プレフィックスが付きます。これは、(a)10進数とより一貫性があり、(b)バイナリ値が使用される可能性が最も高い方法とより互換性があります。 2の補数表現を使用して負の数を指定する機能は失われますが、2の補数はstorage implementationの詳細であり、基礎となる価値そのもの。ユーザーが理解する必要があるものである必要はありません。

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

64
tylerl

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

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

14
casevh
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)

W.J。Van de Laan's コメントから修正)

3
AJP

あなたが最終的に何をしたいのか、私には完全にはわかりませんが、 bitarray パッケージを見たいかもしれません。

2
user1245262

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

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)
1
def tobin(data, width):
    data_str = bin(data & (2**width-1))[2:].zfill(width)
    return data_str
1
Enze Chi

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

bin(5)[2:] '101'

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

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

あるいは

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

1
user3181121

タイラーの非常に有用な回答の修正。正の数と負の数(エラーチェックなし)の符号拡張を提供します。

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'
1
pev.hall

必要はありません、すでにあります。 python異なる表現を選択することです。各ニブルを個別に印刷し始めると、その真の色が表示されます。

checkNIB = '{0:04b}'.format
checkBYT = lambda x: '-'.join( map( checkNIB, [ (x>>4)&0xf, x&0xf] ) ) 
checkBTS = lambda x: '-'.join( [ checkBYT( ( x>>(shift*8) )&0xff ) for shift in reversed( range(4) ) if ( x>>(shift*8) )&0xff ] )


print( checkBTS(-0x0002) )

出力は簡単です:

>>>1111-1111-1111-1111-1111-1111-1111-1110  

ニブルの2の補数を表示したい場合、元の表示に戻りますが、ニブルの半分に分割することも可能です。 最良の結果は負の16進数および2進整数の解釈であることに留意してくださいそれほど多くない単純な数値、hexでもバイトサイズを設定できます。

1
Danilo

Tylerl answer のもう少し読みやすいバージョンを次に示します。たとえば、-28-bitsの否定表現2の補数」

bin(-2 & (2**8-1))

2 ** 8は9番目のビット(256)を表し、1を減算し、先行するすべてのビットを1(255)に設定します

8および16ビットマスクの場合、(2 ** 8-1)を0xffまたは0xffffに置き換えることができます。 16進バージョンは、その時点以降は読み取り可能になります。

これが不明な場合は、通常の機能を次に示します。

def twosComplement (value, bitLength) :
    return bin(value & (2**bitLength - 1))
0
Nicolas David