Seite 1 von 1

Decimal Implementierung

Verfasst: Montag 12. Juli 2010, 08:52
von frabron
Hallo,

ich habe mir eine Klasse geschrieben, die mir das Rechnen mit Gewichten ermöglicht à la 0.2g + 2.1 kg = 2.3kg. Für die Klasse habe ich auch die Rich Comparison Methoden implementiert. Jetzt ist mir bei Vergleichtests aufgefallen, dass Gewichte, die gleich sein sollten, nicht gleich sind. Schuld ist wohl die Floating Point Problematik. Ich konnte das Problem folgendermaßen isolieren:

Code: Alles auswählen

>>> foo = 0.0238
>>> bar = 0.022 + 0.0018
>>> foo == bar
False
Nun kann ich ja mittels Decimal beim Vergleichen ein "richtiges" Ergebnis erhalten:

Code: Alles auswählen

>>> foo = Decimal(str(0.0238))
>>> bar = Decimal(str(0.022)) + Decimal(str(0.0018))
>>> foo == bar
True
Wie kann ich jetzt "Decimal" am besten in meinen bestehenden Code implementieren, um Gewichte vergleichen zu können? Einfach jede Berechnung in Decimal konvertieren? Oder kann man da geschickt etwas mit Vererbung machen, indem man von Decimal erbt? Ungeschickter Weise habe ich den Code leider zu Hause auf meinem Rechner gelassen und kann erst heute abend die Klasse posten. Deshalb aus dem Kopf:

Code: Alles auswählen

class Weight(object):
    def __init__(self, value, unit="g"):
        self.value = value
        self.unit = unit
        self.si_prefix = unit[0:1]
        self.si_prefixes = { 'µ' : 6, 'm': 3, 'k': -3}

    @property
    def base_value(self):
        # so ungefähr ;-)
        # genaueres später
        if self.unit == "g":
            return self.value
        else:
            return self.value * 10**(self.si_prefixes[self.si_prefix]*-1)
Würde es bereits aureichen, self.value als Decimal zu schreiben? Denn man kann ja so weiterrechnen ...

Code: Alles auswählen

>>> bar * 2
Decimal('0.0476')
Danke,

Frank

Re: Decimal Implementierung

Verfasst: Montag 12. Juli 2010, 09:59
von Trichter
Wie es aussieht musst du alle Werte mit denen du rechnest in Decimals umwandeln.
Wenn du mit Decimals und Integer Werten arbeitest kannst du die Typen zwar mischen, aber mit Werten vom Typ float geht das schon nicht mehr.

Code: Alles auswählen

>>> a = d.Decimal("5.3")
>>> a
Decimal("5.3")
>>> a * 10.4
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: unsupported operand type(s) for *: 'Decimal' and 'float'
>>> 

Re: Decimal Implementierung

Verfasst: Montag 12. Juli 2010, 17:48
von frabron
So geht das jetzt:

Code: Alles auswählen

class Weight(object):

    def __init__(self, value, unit="g"):
        self.value = Decimal(str(value))
        self.unit = unit
        self.si_prefix = self.unit[0:1]

        self.si_factors = {
            "n" : Decimal(str(9)),
            "µ" : Decimal(str(6)),
            "m" : Decimal(str(3)),
            "k" : Decimal(str(-3))
        }

    @property
    def base_value(self):
        """convert to gramm"""

        if self.unit == self.si_prefix:
            return self.value
        else:
            return self.value * 10**(self.si_factors[self.si_prefix]
                                     * Decimal(str(-1)))

    def __eq__(self, weight):
        return self.base_value == weight.base_value
erlaubt jetzt auch

Code: Alles auswählen

    bar = Weight(23.8, "mg")
    foo = Weight(1.8, "mg") + Weight(22, "mg")
    print foo == bar
True