Zahlen in andere Zahlensysteme umwandeln

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

Freitag 13. Juni 2008, 21:39

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: 4871
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Freitag 13. Juni 2008, 22:08

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: 2479
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Freitag 13. Juni 2008, 22:09

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

Freitag 13. Juni 2008, 22:18

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: 2479
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Freitag 13. Juni 2008, 22:31

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

Samstag 14. Juni 2008, 20:39

Was spricht eigentlich gegen

Code: Alles auswählen

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

Samstag 14. Juni 2008, 21:22

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

Sonntag 15. Juni 2008, 10:06

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

Sonntag 15. Juni 2008, 10:31

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:

Sonntag 15. Juni 2008, 11:14

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

Sonntag 15. Juni 2008, 18:50

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:

Sonntag 15. Juni 2008, 19:07

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

Sonntag 15. Juni 2008, 22:23

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: 4871
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Sonntag 15. Juni 2008, 22:28

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

Sonntag 15. Juni 2008, 23:20

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