Zahlen in andere Zahlensysteme umwandeln

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Ich hab ein kleines Programm/Modul geschrieben um Zahlen in ein anderes Zahlensystem umzuwandeln. Die Idee kam mir als wir genau das für einige Zahlen von Hand als Hausaufgabe machen sollten(Mathe/Informatik). Unterstützt werden Zahlensysteme von 2(binär) bis 16(hexadezimal).
http://paste.pocoo.org/show/69205/
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ich will dich ja nicht enttäuschen, aber die int-Funktion kann das alles schon.

Und warum hast du das denn in eine Klasse gepack? Wenn wenigstens die convert-Methode per Parameter Zahlen entgegennehmen könnte wäre es noch verständlich aber so ist es total sinnlos.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Ich fand das mit der Klasse sinnvoller, da ich dazu noch eine GUI schreiben wollte.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

DasIch hat geschrieben:Ich fand das mit der Klasse sinnvoller, da ich dazu noch eine GUI schreiben wollte.
Wenn ich dich richtig verstehe, dann willst du auch noch die GUI und die Logik vermischen, dass ist ein richtig grausamer Bruch mit vernünftigem Design ;-) Was spricht denn dagegen eine Klasse einzuführen, die mit der Umwandlungsfunktion arbeitet, dann kannst du letztere auch wiederverwenden.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Ich wollte diesen Code eigentlich als Modul importieren und convert() nutzen um das Ergebnis zu bekommen. Was ist daran den so grausam?
abgdf

Was spricht eigentlich gegen

Code: Alles auswählen

python -c 'print 0x4e'
z.B. für Hex -> Dec ? Usw.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

abgdf hat geschrieben:Was spricht eigentlich gegen

Code: Alles auswählen

python -c 'print 0x4e'
z.B. für Hex -> Dec ? Usw.
Ehrlich gesagt wusste ich nicht dass das geht aber so hätte ich auch den algorithmus dahinter nicht verstanden ;)

Ich hab mal eine neue Version gemacht. Die Zahlen/Zahlensysteme werden überprüft und außerdem nur Zahlensysteme bis einschliesslich Base-16 unterstützt. Das wurde vorher zwar einfach ignoriert ich bin mir aber nicht sicher ob das so sauber ist...

Mich würde mal interessieren was ihr von dem Teil in Zeile 16ff. haltet? Ist das sauber die Dictionarys so zu erzeugen obwohl ich die Werte eigentlich schon vorher kenne?

http://paste.pocoo.org/show/70033/

P.S.:Einige Kommentare sind eigentlich nur dafür da damit mein Lehrer der kein Python kann das ganze auch versteht ;)
lunar

Ein tolles Beispiel für Klassenmissbrauch ... es zeigt wunderbar, wie man sowas in Java löst und wie man es in Python _nicht_ lösen sollte. Lass mich raten, dass kommt jetzt auch in eine eigene Datei namens "Number.py"?

Wenn dein Lehrer dir gesagt hat, dass das in eine Klasse gehört, dann solltest du ihm mal erklären, dass Python _nicht_ Java ist.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

DasIch hat geschrieben:P.S.:Einige Kommentare sind eigentlich nur dafür da damit mein Lehrer der kein Python kann das ganze auch versteht ;)
Würde dein Lehrer das nicht vielleicht einfacher verstehen, wenn das nicht so viel Code wäre? Warum für 10 und 16 je ein Sonderfall? Wozu das Dictionary? Wozu die komplizierten Array-Operationen? In der Kürze liegt die Würze!

Ich vermute, ein `int(input, base)` zum Einlesen wäre zu einfach, da es um den Algorithmus dahinter geht. Eine Zahl in eine Stringrepräsentation zu einer bestimmten Basis zu verwandeln kann Python leider nicht direkt. Zumindest dort braucht man einen.

Iterativ ist es je ein Dreizeiler:

Code: Alles auswählen

_digits = "0123456789abcdefghijklmnopqrstuvwxyz"

def intN(s, b):
    i = 0
    for c in s: i = i * b + _digits[:b].index(c)
    return i
    
def strN(i, b):
    s = ""
    while i: s = _digits[:b][i % b] + s; i /= b
    return s or "0"
Eleganter für `intN` finde ich einen funktionalen Ansatz:

Code: Alles auswählen

def intN(s, b): return reduce(lambda i, c: i * b + c, (_digits[:b].index(c) for c in s))
Stefan
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

Hab letztens auch so'ne Funktion geschrieben... vielleicht kann man ja damit was anfangen:

Code: Alles auswählen

from __future__ import division

def baserepr(nr, base):
    sysnr = [str(x) for x in xrange(0, 10)] + \
            [chr(65+x) for x in xrange(0, 26)]
    endnr = str()
    while nr > 0:
        endnr += sysnr[nr % base]
        nr = nr // base
    return endnr[::-1] or "0"

Eine Klasse für sowas zu schreiben... würde ich höchstens, wenn mir wirklich unfassbar langweilig ist und ich zeigen möchte, wann Klassen absolut überflüssig sind.

(Funktioniert natürlich nicht so leicht mit Fließkomma- und negativen Zahlen.... Aber halt... für'n Anfang.)
abgdf

Also,

einerseits haben wir:

Code: Alles auswählen

python -c 'print int("110110", 2)'
python -c 'print int("255", 8)'
python -c 'print int("FF", 16)'
und

Code: Alles auswählen

python -c 'print oct(25)'
python -c 'print hex(25)'
Und dann die allgemeine Funktion von BlackVivi: Für mich war sie so etwas schwer zu verstehen (bist du Perlianer ?); ich hab' sie deshalb für mich nochmal etwas vereinfacht (möglicherweise Performanceeinbußen):

Code: Alles auswählen

#!/usr/bin/env python

import string

def baserepr(nr, base):

    a = string.digits + string.ascii_uppercase

    b = ""

    while nr > 0:
        b += a[nr % base]
        nr = int(nr / base)

    # Reversing b:

    c = ""

    for i in range(len(b)):
        c += b[len(b) - 1 - i]

    return c or "0"

print baserepr(254, 16)
Cool, brauchte ich für Binär !

Viele Grüße
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

Die Zahlen und Buchstaben konnte man mithilfe von ``string`` zusammensetzen, das stimmt wohl... Aber das umdrehen machst du dir viel zu schwierig. Könntest auch einfach reversed(<liste>) verwenden oder so.
abgdf

Ok; hab' noch was entdeckt:

Code: Alles auswählen

c = ""
for i in reversed(b):
    c += i
Ist sicher Geschmackssache.

Diese Zahlenumwandlungen "brauche" ich übrigens für mein kleines "Dungeon"-Projekt:

http://www.python-forum.de/topic-7603.html

Dort versuche ich, in einer einzigen Zahl den Status eines Feldes, auf dem sich der Spieler, bzw. dessen Party befindet, zu speichern. Das Feld hat vier Seiten, dann würde "1101" z.B. bedeuten, links, oben und unten sind Wände (1), nach "rechts" ist es frei, dorthin könnte der Spieler weitergehen.
Komplizierter wird's, wenn ich noch offene und geschlossene Türen, Schätze, Fallen und Monster einbauen will. Hier bieten sich höhere Zahlen (und Zahlensysteme) an, z.B. "1201": Links und unten Wände (1), rechts nichts (0), oben eine geschlossene Tür. Und so weiter ...

Viele Grüße
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

abgdf hat geschrieben:Ok; hab' noch was entdeckt:

Code: Alles auswählen

c = ""
for i in reversed(b):
    c += i
Ist sicher Geschmackssache.
Und das ist jetzt genau wo besser lesbarer oder einfacher als

Code: Alles auswählen

c = b[::-1]
?
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Das erinnert mich irgendwie ein bischen an das hier:

Code: Alles auswählen

#Enterprise programmer
def new(cls, *args, **kwargs):
    return cls(*args, **kwargs)

class Number(object):
    pass

class IntegralNumber(int, Number):
    def toInt(self):
        return new (int, self)

class InternalBase(object):
    def __init__(self, base):
        self.base = base.toInt()

    def getBase(self):
        return new (IntegralNumber, self.base)

class MathematicsSystem(object):
    def __init__(self, ibase):
        Abstract

    @classmethod
    def getInstance(cls, ibase):
        try:
            cls.__instance
        except AttributeError:
            cls.__instance = new (cls, ibase)
        return cls.__instance

class StandardMathematicsSystem(MathematicsSystem):
    def __init__(self, ibase):
        if ibase.getBase() != new (IntegralNumber, 2):
            raise NotImplementedError
        self.base = ibase.getBase()

    def calculateFactorial(self, target):
        result = new (IntegralNumber, 1)
        i = new (IntegralNumber, 2)
        while i <= target:
            result = result * i
            i = i + new (IntegralNumber, 1)
        return result

print StandardMathematicsSystem.getInstance(new (InternalBase, new (IntegralNumber, 2))).calculateFactorial(new (IntegralNumber, 6)) 
Darauf kannst du ja aufbauen ;)
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

audax hat geschrieben:Darauf kannst du ja aufbauen ;)
Ein "bisschen" schwer verständlich...
btw. ist mein Code wirklich soo schlimm?
Ich hab irgendwie das Gefühl das meine Denkweise ein Problem zu lösen einfach unnötig kompliziert ist und so sieht dann auch mein Code aus.
Hat vielleicht jemand einen Tipp wie man sich das abgewöhnen kann? :lol:
Redprince
User
Beiträge: 128
Registriert: Freitag 22. Oktober 2004, 09:22
Wohnort: Salzgitter
Kontaktdaten:

Abgewöhnen vielleicht nicht, aber Besserung verschafft mit Sicherheit jede Menge Übung, wie das bei vielen Dingen im Leben so ist ;)
Mir hilft es ferner oft, entsprechenden Code einfach mal eine Zeit lang unangetastet zu lassen und dann mit freiem Geiste noch einmal anzusehen..
I am not part of the allesburner. I am the [url=http://allesburner.de]allesburner[/url].
abgdf

Und das ist jetzt genau wo besser lesbarer oder einfacher als
c = b[::-1]
?
Wenn ich "c = b[::-1]" zum ersten Mal lese, ist das für mich nur so ein kryptischer Shortcut, der nicht aus sich heraus verständlich ist. In der Philosophie von bash und Perl ist das ok, aber in Python bemühe ich mich, so zu schreiben, daß mir auch nach Monaten klar wird, was da vor sich geht.
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

abgdf hat geschrieben:
Und das ist jetzt genau wo besser lesbarer oder einfacher als
c = b[::-1]
?
Wenn ich "c = b[::-1]" zum ersten Mal lese, ist das für mich nur so ein kryptischer Shortcut, der nicht aus sich heraus verständlich ist. In der Philosophie von bash und Perl ist das ok, aber in Python bemühe ich mich, so zu schreiben, daß mir auch nach Monaten klar wird, was da vor sich geht.
Für mich ist die Slicing Syntax nach den ersten 5 Minuten klar gewesen, das hat sich bis heute nicht geändert o_o [Start:Ende:Schritte]. Wenn man es nicht angibt, is's nich grossartig anders.
Antworten