Umwandlung binär <-> dezimal

Code-Stücke können hier veröffentlicht werden.
Antworten
Benutzeravatar
snafu
User
Beiträge: 6862
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Mit Version 2.6 hat Python ein Builtin erhalten, das Dezimalzahlen in Binärzahlen umwandeln kann. Ich fand allerdings die Ausgabe etwas komisch:

Code: Alles auswählen

In [1]: bin(267)
Out[1]: '0b100001011'

In [2]: bin(-267)
Out[2]: '-0b100001011'
Deshalb hab ich mir etwas Kosmetik geschrieben:

Code: Alles auswählen

def binary(number):
    return int(''.join(bin(number).split('0b')))
Ergebnis:

Code: Alles auswählen

In [3]: import binary

In [4]: binary.binary(267)
Out[4]: 100001011

In [5]: binary.binary(-267)
Out[5]: -100001011
Ich bin allerdings kein Mathematiker. Vielleicht ist die Pythonausgabe aus irgendwelchen Gründen besser. Würd mich dann interessieren, warum das so ist...

Eine umgekehrte Funktion hab ich nicht in Python gefunden und sie daher selbst implementiert:

Code: Alles auswählen

def bin2dec(binary):
    return sum(int(state) * 2**e
               for (e, state) in enumerate(reversed(str(binary))))
Die Zahl wird also zunächst in eine iterierbare Sequenz (ein String) umgewandelt und anschließend umgekehrt, damit der Index als Exponent genutzt werden kann. Wenn jemandem eine bessere Lösung einfällt, dann her damit. ;P

Code: Alles auswählen

In [6]: binary.bin2dec(100001011)
Out[6]: 267
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

Code: Alles auswählen

>>> x = bin(267)
>>> x
'0b100001011'
>>> eval(x)
267
Ich denke mal, dass man bei ``bin`` die Binärdarstellung wollte und ``100001011`` ist ja ein int. Naja, keine Ahnung :)
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
Benutzeravatar
snafu
User
Beiträge: 6862
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ich find's nicht gerade einleuchtend, dass `eval()` die Rückumwandlung macht, aber nagut, dann gibt's das ja schon.

Achso, bei `hex()` gibt's das z.B. auch. Kannte ich alles noch nicht.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

snafu hat geschrieben:Ich find's nicht gerade einleuchtend, dass `eval()` die Rückumwandlung macht
eval() braucht es dafür auch nicht:

Code: Alles auswählen

>>> bin(267)
'0b100001011'
>>> int(_,2)
267
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

Warum erkennt ``int`` das ``0b`` nicht, bzw. warum muss man ``base=2`` mit angeben?
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
Benutzeravatar
snafu
User
Beiträge: 6862
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

jbs hat geschrieben:warum muss man ``base=2`` mit angeben?
Also mir fällts gerade wie Äpfel aus den Augen.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

snafu hat geschrieben:Ich bin allerdings kein Mathematiker. Vielleicht ist die Pythonausgabe aus irgendwelchen Gründen besser. Würd mich dann interessieren, warum das so ist...
Der Grund ist recht einfach: In einem Integer werden Werte gespeichert (zu welcher Basis auch immer). Wenn du einen Integer zum Beispiel mittels "print" ausgibst, dann wird dieser im Dezimalsystem dargestellt. Du wandelst die binäre Darstellung hingegen nur so um dass sie im Dezimalsystem binär aussieht. Das Problem wird hier deutlich:

Code: Alles auswählen

>>> a = 15
>>> b = 7
>>> print a + b
22
>>> print binary(a) + binary(b)
1222
Bei der letzten Ausgabe würde man natürlich 10110 erwarten und nicht 1222.
Das Leben ist wie ein Tennisball.
Benutzeravatar
snafu
User
Beiträge: 6862
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

`int(bin(a) + bin(b), 2)` gibt allerdings auch nen ValueError. Man bräuchte vielleicht einen eigenen Datentyp für binäre Zahlen.

Nur auf dem Weg gehts:

Code: Alles auswählen

In [47]: int(bin(a), 2) + int(bin(b), 2)
Out[47]: 22
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Richtig, weil es Strings sind und es sich um eine DARSTELLUNG handelt. Binäre Zahlen brauchen keinen eigenen Datentyp, das sie keine eigenen Typen sind. Sie sind nur die Darstellung einer Zahl!

Es ist vollkommen egal ob du
42 zur Basis 10 oder
101010 zur Basis 2 schreibst.

Es ist zweimal der selbe Wert, nur mit verschiedenen Basen.
Das Leben ist wie ein Tennisball.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

snafu hat geschrieben:Man bräuchte vielleicht einen eigenen Datentyp für binäre Zahlen.
Ich hab seinerzeit mal so etwas zur Übung gemacht: http://www.python-forum.de/topic-13891.html
Benutzeravatar
snafu
User
Beiträge: 6862
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ich dachte halt an etwas in der Art `b"100011010"`, ähnlich wie man das bei Unicode mit dem `u` kennt. Ich finde das jedenfalls mit den Strings nicht gerade elegant gelöst. Aber vielleicht lieg ich da auch falsch. Die Mehrheit scheint ja eher dagegen zu sein.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

snafu hat geschrieben:Ich dachte halt an etwas in der Art `b"100011010"`, ähnlich wie man das bei Unicode mit dem `u` kennt.
Sowas gibts in Python 2.6 und Python 3 ;)
snafu hat geschrieben:Die Mehrheit scheint ja eher dagegen zu sein.
Ja, finde ich auch eher unnütz. Letztens bin ich drüber gestolpert, dass GCC 0b...-Literale unterstützt um dann kurz darauf auf die Nase zu fliegen weil das Indentation-Tool damit nicht zurecht kommt (sind wie sich rausstellt nonstandard) und damit sind die auch Prompt wieder aus meinem Code verschwunden. In Python fände ich es praktischer wenn man Hexadezimal und Oktalliterale entfernen würde und das parsen dann von einem Builtin wie ``int()`` erledigen lässt. Im Gegensatz zu C braucht man Hexadezimalzahlen in Python ganz selten und Oktalzahlen nahezu nie.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
BlackJack

@jbs: Das ``base=2`` braucht man, weil der Default-Wert von dem Argument 10 ist. Und ich würde mich beschweren, wenn `int()` dann aus der Eingabe "0b11" etwas anderes als eine Ausnahme machen würde, oder schlimmer noch: wenn aus der Eingabe "09" ein `ValueError` und keine 9 werden würde. Denn so etwas wäre mir beim Parsen von Datumsangaben sicher schonmal um die Ohren geflogen.

Wenn man als `base` die 0 angibt, dann parst `int()` eine Zeichenkette so wie der Compiler das im Quelltext machen würde.
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

Verstanden. Danke.
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
Benutzeravatar
snafu
User
Beiträge: 6862
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Leonidas hat geschrieben:
snafu hat geschrieben:Ich dachte halt an etwas in der Art `b"100011010"`, ähnlich wie man das bei Unicode mit dem `u` kennt.
Sowas gibts in Python 2.6 und Python 3 ;)
Also unter Python 2.6 hat mir `bin()` den eingangs genannten String zurückgegeben. Oder hab ich dich jetzt falsch verstanden?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

snafu hat geschrieben:
Leonidas hat geschrieben:
snafu hat geschrieben:Ich dachte halt an etwas in der Art `b"100011010"`, ähnlich wie man das bei Unicode mit dem `u` kennt.
Sowas gibts in Python 2.6 und Python 3 ;)
Also unter Python 2.6 hat mir `bin()` den eingangs genannten String zurückgegeben. Oder hab ich dich jetzt falsch verstanden?
Damit habe ich scherzweise gemeint dass Python 3 und Python 2.6 (mit ``from __future__ import unicode_literals``) Byte-Literale haben, die eben das angesprochene Format haben :)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten