it-swarm.com.de

Zweierkomplement Binary in Python?

Zahlen in Python werden in Zweierkomplementen gespeichert, richtig?

Obwohl:

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

Und:

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

Das ist ziemlich lahm. Wie bekomme ich Python, um mir die Zahlen in REAL-Binär-Bits und ohne die 0b davor zu geben? So:

>>> x = 5
>>> bin(x)
0101
>>> y = -5
>>> bin(y)
1011
29
Thor Correia

Sie sind sich nicht sicher, wie Sie mit der Standard-Bibliothek das bekommen, was Sie möchten. Es gibt eine Handvoll Skripte und Pakete, die die Konvertierung für Sie erledigen.

Ich wollte nur das "Warum" beachten und warum es nicht lahm ist.

bin () gibt keine binären Bits zurück. es wandelt die Zahl in eine binäre Zeichenfolge um. Die führende '0b' teilt dem Interpreter mit, dass Sie gemäß der Definition der Python-Sprache mit einer Binärzahl zu tun haben. Auf diese Weise können Sie direkt mit Binärzahlen wie dieser arbeiten 

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

das ist nicht lahm das ist großartig.


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

bin (x)

Konvertieren Sie eine Ganzzahl in eine Binärzeichenfolge. 

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

Integer- und Long Integer-Literale werden durch die folgenden lexikalischen Definitionen beschrieben:

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

bindigit :: = "0" | "1"

2

Am besten funktioniert es, wenn Sie eine Maske angeben. Auf diese Weise legen Sie fest, wie weit die Signatur verlängert werden soll.

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

Oder vielleicht allgemeiner:

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

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

In der Grundtheorie hängt die tatsächliche Breite der Zahl von der Größe des Speichers ab. Wenn es sich um eine 32-Bit-Zahl handelt, hat eine negative Zahl im MSB eines Satzes von 32 eine 1. Wenn es sich um einen 64-Bit-Wert handelt, sind 64 Bit anzuzeigen. 

In Python ist die Ganzzahlgenauigkeit jedoch nur auf die Einschränkungen Ihrer Hardware beschränkt. Auf meinem Computer funktioniert dieses zwar, aber es verbraucht 9 GB RAM, nur um den Wert von x zu speichern. Alles höher und ich bekomme einen MemoryError. Wenn ich mehr RAM hätte, könnte ich größere Zahlen speichern.

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

Welche Binärzahl steht also für -1? Python ist in der Lage, Millionen (und sogar Milliarden) Präzisionsteile buchstäblich zu interpretieren, wie das vorige Beispiel zeigt. Im Zweierkomplement erstreckt sich das Vorzeichenbit ganz nach links, aber in Python gibt es keine vordefinierte Anzahl von Bits. es gibt so viele wie du brauchst.

Dann geraten Sie jedoch in die Mehrdeutigkeit: Stellt der 1 für 1 oder -1 dar? Nun, es könnte entweder sein. Ist 1117 oder -1? Wieder könnte es entweder sein. Also, 111111111 stellt 511 oder -1... dar, beides, abhängig von Ihrer Genauigkeit. 

Python benötigt eine Möglichkeit, diese Zahlen binär darzustellen, damit ihre Bedeutung nicht eindeutig ist. Das 0b-Präfix sagt nur "diese Zahl ist binär". Genau wie 0x bedeutet "diese Zahl ist in Hex". Wenn ich also 0b1111 sage, woher weiß ich, ob der Benutzer -1 oder 15 will? Es gibt zwei Möglichkeiten:

Option A: Das Vorzeichenbit
Sie können erklären, dass alle Zahlen vorzeichenbehaftet sind und das ganz linke Bit das Vorzeichenbit ist. Das bedeutet, 0b1 ist -1, während 0b01 1 ist. Das bedeutet auch, dass 0b111 ebenfalls -1 ist, während 0b0111 7 ist. Am Ende ist dies wahrscheinlich eher verwirrend als hilfreich, insbesondere weil die meisten Binärarithmetik vorzeichenlos ist trotzdem und Menschen stoßen häufiger auf Fehler, wenn sie versehentlich eine Zahl als negativ markieren, weil sie kein explizites Vorzeichenbit enthalten.

Option B: Die Zeichenanzeige
Bei dieser Option werden Binärzahlen ohne Vorzeichen dargestellt, und negative Zahlen haben ein "-" - Präfix, genau wie in Dezimalzahlen. Dies ist (a) eher mit Dezimalzahlen vereinbar, (b) mit der Art und Weise, wie Binärwerte am wahrscheinlichsten verwendet werden, kompatibel. Sie verlieren die Möglichkeit, eine negative Zahl mithilfe der Zweierkomplementdarstellung anzugeben. Denken Sie jedoch daran, dass das Zweierkomplement eine storage-Implementierung ist und kein richtiger Hinweis auf den zugrunde liegenden Wert selbst ist. Es sollte nicht etwas sein, das der Benutzer verstehen muss. 

Am Ende ist Option B am sinnvollsten. Es gibt weniger Verwirrung und der Benutzer muss die Speicherdetails nicht verstehen.

56
tylerl

Um eine binäre Sequenz richtig als Zweierkomplement zu interpretieren, muss der Sequenz eine Länge zugeordnet werden. Wenn Sie Low-Level-Typen bearbeiten, die direkt CPU-Registern entsprechen, gibt es eine implizite Länge. Da Python-Ganzzahlen eine beliebige Länge haben können, gibt es kein internes Zweierkomplement-Format. Da einer Länge keine Länge zugeordnet ist, kann zwischen positiven und negativen Zahlen nicht unterschieden werden. Um die Mehrdeutigkeit zu entfernen, enthält bin () ein Minuszeichen, wenn eine negative Zahl formatiert wird.

Der ganzzahlige Typ mit beliebiger Länge von Python verwendet tatsächlich ein internes Format mit Vorzeichengröße. Die logischen Operationen (Bitverschiebung und und oder usw.) sind so gestaltet, dass sie das Zweierkomplement-Format nachahmen. Dies ist typisch für mehrere Präzisionsbibliotheken.

13
casevh
tobin = lambda x, count=8: "".join(map(lambda y:str((x>>y)&1), range(count-1, -1, -1)))

z.B.

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

Oder als klare Funktionen:

# 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)

(Angepasst von W.J. Van de Laans Kommentar)

3
AJP

Ich bin nicht ganz sicher, was Sie letztendlich tun möchten, aber Sie möchten vielleicht das Paket bitarray ansehen.

2
user1245262

Für positive Zahlen verwenden Sie einfach:

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

Bei negativen Zahlen ist es etwas anders:

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

Als Ganzes sollte es so aussehen:

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

Verwenden Sie Scheiben, um unerwünschte '0b' loszuwerden.

bin(5)[2:] '101'

oder wenn Sie Ziffern möchten,

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

oder auch

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

1
user3181121

Eine Änderung an der sehr hilfreichen Antwort von Tylerl, die eine Vorzeichenerweiterung für positive Zahlen sowie für negative Werte (keine Fehlerprüfung) bietet.

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

Beispiel:

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

In [12]: to2sCompStr(24, 18)
Out[12]: '000000000000011000'
1
pev.hall

Keine Notwendigkeit, ist es schon. Es ist nur ein Python, der sich dafür entscheidet, es anders darzustellen. Wenn Sie jedes Nibble separat drucken, werden seine echten Farben angezeigt.

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

Ausgabe ist einfach: 

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

Jetzt wird wieder die ursprüngliche Darstellung angezeigt, wenn Sie zwei Ergänzungen eines Nibbles anzeigen möchten. Es ist jedoch immer noch möglich, wenn Sie es in Nibble-Hälften teilen. Denken Sie daran, dass das beste Ergebnis bei negativen Hex- und Binär-Integer-Interpretationen ist einfache Zahlen nicht so sehr, auch bei Hex Sie können die Byte-Größe einstellen. 

1
Danilo

Hier ist eine etwas lesbarere Version von Tylerl answer . Angenommen, Sie möchten -2 in ihrer 8-Bit negativen Darstellung von "Zweierkomplement":

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

2 ** 8 steht für das neunte Bit (256), subtrahieren 1, und Sie haben alle vorhergehenden Bits auf Eins gesetzt (255).

für 8- und 16-Bit-Masken können Sie (2 ** 8-1) durch 0xff oder 0xffff ersetzen. Die hexadezimale Version wird nach diesem Punkt weniger lesbar.

Wenn dies unklar ist, ist dies eine regelmäßige Funktion davon:

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