decimal — Dezimale Festkomma- und Gleitkommaarithmetik

Quellcode: Lib/decimal.py


Das Modul decimal unterstützt schnelle, korrekt gerundete dezimale Gleitkommaarithmetik. Es bietet mehrere Vorteile gegenüber dem Datentyp float:

  • Decimal „beruht auf einem Gleitkommamodell, das mit dem Menschen im Blick entworfen wurde und notwendigerweise einem obersten Leitgedanken folgt: Computer müssen eine Arithmetik bereitstellen, die genauso arbeitet wie die Arithmetik, die Menschen in der Schule lernen.“ – Auszug aus der Spezifikation der Dezimalarithmetik.

  • Dezimalzahlen lassen sich genau darstellen. Zahlen wie 1.1 und 2.2 haben im binären Gleitkomma dagegen keine genaue Darstellung. Endbenutzer erwarten normalerweise nicht, dass 1.1 + 2.2 als 3.3000000000000003 erscheint, wie es beim binären Gleitkomma der Fall ist.

  • Diese Genauigkeit überträgt sich auf die Arithmetik. Im dezimalen Gleitkomma ist 0.1 + 0.1 + 0.1 - 0.3 genau gleich null. Im binären Gleitkomma lautet das Ergebnis 5.5511151231257827e-017. Das liegt zwar nahe bei null, doch die Abweichungen verhindern zuverlässige Gleichheitsprüfungen und können sich aufsummieren. Daher ist Decimal in Buchhaltungsanwendungen mit strengen Gleichheitsinvarianten die bessere Wahl.

  • Das Modul decimal kennt den Begriff der signifikanten Stellen, sodass 1.30 + 1.20 gleich 2.50 ist. Die abschließende Null bleibt erhalten, um die Signifikanz anzuzeigen. So ist es bei Geldbeträgen üblich. Beim Multiplizieren verwendet der „Schulbuch“-Weg alle Stellen der Faktoren: 1.3 * 1.2 ergibt 1.56, während 1.30 * 1.20 1.5600 ergibt.

  • Anders als das hardwaregestützte binäre Gleitkomma hat das Modul decimal eine vom Benutzer veränderliche Genauigkeit – voreingestellt 28 Stellen –, die so groß sein darf, wie es ein Problem erfordert:

    >>> from decimal import *
    >>> getcontext().prec = 6
    >>> Decimal(1) / Decimal(7)
    Decimal('0.142857')
    >>> getcontext().prec = 28
    >>> Decimal(1) / Decimal(7)
    Decimal('0.1428571428571428571428571429')
    
  • Sowohl binäres als auch dezimales Gleitkomma sind anhand veröffentlichter Standards umgesetzt. Während der integrierte Typ float nur einen bescheidenen Teil seiner Fähigkeiten offenlegt, legt das Modul decimal alle verlangten Teile des Standards offen. Bei Bedarf hat der Programmierer die volle Kontrolle über Rundung und Signalbehandlung. Dazu gehört die Möglichkeit, genaue Arithmetik zu erzwingen, indem Ausnahmen jede ungenaue Operation unterbinden.

  • Das Modul decimal wurde entworfen, um „ohne Vorrang sowohl genaue, ungerundete Dezimalarithmetik – manchmal Festkommaarithmetik genannt – als auch gerundete Gleitkommaarithmetik“ zu unterstützen. – Auszug aus der Spezifikation der Dezimalarithmetik.

Der Entwurf des Moduls dreht sich um drei Begriffe: die Dezimalzahl, den Kontext für die Arithmetik und die Signale.

Eine Dezimalzahl ist unveränderlich. Sie hat ein Vorzeichen, Koeffizientenziffern und einen Exponenten. Um die Signifikanz zu erhalten, werden abschließende Nullen der Koeffizientenziffern nicht abgeschnitten. Decimals umfassen auch besondere Werte wie Infinity, -Infinity und NaN. Der Standard unterscheidet außerdem -0 von +0.

Der Kontext für die Arithmetik ist eine Umgebung, die Genauigkeit, Rundungsregeln, Grenzen für Exponenten, Flags für die Ergebnisse von Operationen und Trap-Schalter festlegt. Letztere bestimmen, ob Signale als Ausnahmen behandelt werden. Zu den Rundungsoptionen gehören ROUND_CEILING, ROUND_DOWN, ROUND_FLOOR, ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_UP und ROUND_05UP.

Signale sind Gruppen von Ausnahmezuständen, die im Laufe einer Rechnung auftreten. Je nach Bedarf der Anwendung lassen sich Signale übergehen, als Hinweis auffassen oder als Ausnahmen behandeln. Die Signale im Modul decimal sind Clamped, InvalidOperation, DivisionByZero, Inexact, Rounded, Subnormal, Overflow, Underflow und FloatOperation.

Zu jedem Signal gehören ein Flag und ein Trap-Schalter. Tritt ein Signal auf, wird sein Flag auf eins gesetzt. Steht dann der Trap-Schalter auf eins, wird eine Ausnahme ausgelöst. Flags sind haftend, der Benutzer muss sie also zurücksetzen, bevor er eine Rechnung beobachtet.

Siehe auch

Tutorial für den schnellen Start

Üblicherweise beginnt die Arbeit mit Decimals damit, das Modul zu importieren, den aktuellen Kontext mit getcontext() anzusehen und bei Bedarf neue Werte für Genauigkeit, Rundung oder eingeschaltete Traps zu setzen:

>>> from decimal import *
>>> getcontext()
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
        capitals=1, clamp=0, flags=[], traps=[Overflow, DivisionByZero,
        InvalidOperation])

>>> getcontext().prec = 7       # Set a new precision

Decimal-Instanzen lassen sich aus ganzen Zahlen, Zeichenketten, Floats oder Tupeln erzeugen. Aus einer ganzen Zahl oder einem Float erzeugt, wird deren Wert genau umgewandelt. Dezimalzahlen umfassen besondere Werte wie NaN, das für „Not a number“ steht, positives und negatives Infinity sowie -0:

>>> getcontext().prec = 28
>>> Decimal(10)
Decimal('10')
>>> Decimal('3.14')
Decimal('3.14')
>>> Decimal(3.14)
Decimal('3.140000000000000124344978758017532527446746826171875')
>>> Decimal((0, (3, 1, 4), -2))
Decimal('3.14')
>>> Decimal(str(2.0 ** 0.5))
Decimal('1.4142135623730951')
>>> Decimal(2) ** Decimal('0.5')
Decimal('1.414213562373095048801688724')
>>> Decimal('NaN')
Decimal('NaN')
>>> Decimal('-Infinity')
Decimal('-Infinity')

Ist das Signal FloatOperation als Trap gesetzt, löst das versehentliche Mischen von Decimals und Floats in Konstruktoren oder Ordnungsvergleichen eine Ausnahme aus:

>>> c = getcontext()
>>> c.traps[FloatOperation] = True
>>> Decimal(3.14)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.5') < 3.7
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.5') == 3.5
True

Added in version 3.3.

Die Signifikanz eines neuen Decimal ergibt sich allein aus der Anzahl der eingegebenen Ziffern. Genauigkeit und Rundung des Kontexts kommen erst bei arithmetischen Operationen ins Spiel.

>>> getcontext().prec = 6
>>> Decimal('3.0')
Decimal('3.0')
>>> Decimal('3.1415926535')
Decimal('3.1415926535')
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85987')
>>> getcontext().rounding = ROUND_UP
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85988')

Werden die inneren Grenzen der C-Fassung überschritten, löst das Erzeugen eines Decimal InvalidOperation aus:

>>> Decimal("1e9999999999999999999")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]

Geändert in Version 3.3.

Decimals arbeiten mit dem größten Teil des übrigen Python gut zusammen. Hier ein kleiner Flying Circus mit dezimalem Gleitkomma:

>>> data = list(map(Decimal, '1.34 1.87 3.45 2.35 1.00 0.03 9.25'.split()))
>>> max(data)
Decimal('9.25')
>>> min(data)
Decimal('0.03')
>>> sorted(data)
[Decimal('0.03'), Decimal('1.00'), Decimal('1.34'), Decimal('1.87'),
 Decimal('2.35'), Decimal('3.45'), Decimal('9.25')]
>>> sum(data)
Decimal('19.29')
>>> a,b,c = data[:3]
>>> str(a)
'1.34'
>>> float(a)
1.34
>>> round(a, 1)
Decimal('1.3')
>>> int(a)
1
>>> a * 5
Decimal('6.70')
>>> a * b
Decimal('2.5058')
>>> c % a
Decimal('0.77')

Decimals lassen sich – mit der integrierten Funktion format() oder mit f-Strings – in Festkomma- oder wissenschaftlicher Schreibweise formatieren, mit derselben Formatierungssyntax (siehe Formatspezifikation Mini-Sprache) wie beim integrierten Typ float:

>>> format(Decimal('2.675'), "f")
'2.675'
>>> format(Decimal('2.675'), ".2f")
'2.68'
>>> f"{Decimal('2.675'):.2f}"
'2.68'
>>> format(Decimal('2.675'), ".2e")
'2.68e+0'
>>> with localcontext() as ctx:
...     ctx.rounding = ROUND_DOWN
...     print(format(Decimal('2.675'), ".2f"))
...
2.67

Außerdem stehen Decimal einige mathematische Funktionen zur Verfügung:

>>> getcontext().prec = 28
>>> Decimal(2).sqrt()
Decimal('1.414213562373095048801688724')
>>> Decimal(1).exp()
Decimal('2.718281828459045235360287471')
>>> Decimal('10').ln()
Decimal('2.302585092994045684017991455')
>>> Decimal('10').log10()
Decimal('1')

Die Methode quantize() rundet eine Zahl auf einen festen Exponenten. Das ist bei Geldbeträgen nützlich, wo Ergebnisse häufig auf eine feste Anzahl von Stellen gerundet werden:

>>> Decimal('7.325').quantize(Decimal('.01'), rounding=ROUND_DOWN)
Decimal('7.32')
>>> Decimal('7.325').quantize(Decimal('1.'), rounding=ROUND_UP)
Decimal('8')

Wie oben gezeigt, greift die Funktion getcontext() auf den aktuellen Kontext zu und erlaubt es, die Einstellungen zu ändern. Für die meisten Anwendungen genügt das.

Für Fortgeschritteneres kann es nützlich sein, mit dem Konstruktor Context() weitere Kontexte zu erzeugen. Um einen davon aktiv zu machen, dient die Funktion setcontext().

Dem Standard entsprechend stellt das Modul decimal zwei einsatzfertige Standardkontexte bereit, BasicContext und ExtendedContext. Der erste ist besonders zur Fehlersuche nützlich, weil viele der Traps eingeschaltet sind:

>>> myothercontext = Context(prec=60, rounding=ROUND_HALF_DOWN)
>>> setcontext(myothercontext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857142857142857142857142857142857142857142857142857142857')

>>> ExtendedContext
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
        capitals=1, clamp=0, flags=[], traps=[])
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857143')
>>> Decimal(42) / Decimal(0)
Decimal('Infinity')

>>> setcontext(BasicContext)
>>> Decimal(42) / Decimal(0)
Traceback (most recent call last):
  File "<pyshell#143>", line 1, in -toplevel-
    Decimal(42) / Decimal(0)
DivisionByZero: x / 0

Kontexte haben außerdem Signal-Flags, um Ausnahmezustände während der Rechnungen zu beobachten. Die Flags bleiben gesetzt, bis sie ausdrücklich geleert werden. Am besten leerst du sie vor jeder Gruppe beobachteter Rechnungen mit der Methode clear_flags().

>>> setcontext(ExtendedContext)
>>> getcontext().clear_flags()
>>> Decimal(355) / Decimal(113)
Decimal('3.14159292')
>>> getcontext()
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
        capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[])

Der Eintrag flags zeigt, dass die rationale Annäherung an pi gerundet wurde – Ziffern jenseits der Genauigkeit des Kontexts wurden verworfen – und dass das Ergebnis ungenau ist, weil einige der verworfenen Ziffern nicht null waren.

Einzelne Traps werden über das Dictionary im Attribut traps eines Kontexts gesetzt:

>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(0)
Decimal('Infinity')
>>> getcontext().traps[DivisionByZero] = 1
>>> Decimal(1) / Decimal(0)
Traceback (most recent call last):
  File "<pyshell#112>", line 1, in -toplevel-
    Decimal(1) / Decimal(0)
DivisionByZero: x / 0

Die meisten Programme passen den aktuellen Kontext nur einmal an, am Programmanfang. In vielen Anwendungen werden die Daten mit einer einzigen Umwandlung in einer Schleife nach Decimal überführt. Sind Kontext gesetzt und Decimals erzeugt, verarbeitet der größte Teil des Programms die Daten genauso wie bei anderen numerischen Typen von Python.

Decimal-Objekte

class decimal.Decimal(value='0', context=None)

Erzeugt ein neues Decimal-Objekt auf Grundlage von value.

value kann eine ganze Zahl, eine Zeichenkette, ein Tupel, ein float oder ein anderes Decimal-Objekt sein. Ohne value wird Decimal('0') zurückgegeben. Ist value eine Zeichenkette, sollte sie der Syntax dezimaler Zahlenzeichenketten entsprechen, nachdem Leerraum am Anfang und Ende sowie Unterstriche überall entfernt wurden:

sign           ::=  '+' | '-'
digit          ::=  '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
indicator      ::=  'e' | 'E'
digits         ::=  digit [digit]...
decimal-part   ::=  digits '.' [digits] | ['.'] digits
exponent-part  ::=  indicator [sign] digits
infinity       ::=  'Infinity' | 'Inf'
nan            ::=  'NaN' [digits] | 'sNaN' [digits]
numeric-value  ::=  decimal-part [exponent-part] | infinity
numeric-string ::=  [sign] numeric-value | [sign] nan

Dort, wo oben digit steht, sind auch andere dezimale Unicode-Ziffern erlaubt. Dazu gehören Dezimalziffern verschiedener anderer Alphabete – etwa arabisch-indische und Devanagari-Ziffern – sowie die Ziffern voller Breite '\uff10' bis '\uff19'. Die Groß- und Kleinschreibung spielt keine Rolle; inf, Inf, INFINITY und iNfINity sind also alle zulässige Schreibweisen für positive Unendlichkeit.

Ist value ein tuple, sollte es drei Bestandteile haben: ein Vorzeichen (0 für positiv, 1 für negativ), ein tuple von Ziffern und einen ganzzahligen Exponenten. Decimal((0, (1, 4, 1, 4), -3)) gibt zum Beispiel Decimal('1.414') zurück.

Ist value ein float, wird der binäre Gleitkommawert verlustfrei in sein genaues dezimales Gegenstück umgewandelt. Diese Umwandlung braucht häufig 53 oder mehr Stellen Genauigkeit. Decimal(float('1.1')) wird zum Beispiel zu Decimal('1.100000000000000088817841970012523233890533447265625').

Die Genauigkeit des context beeinflusst nicht, wie viele Ziffern gespeichert werden. Das bestimmt allein die Anzahl der Ziffern in value. Decimal('3.00000') hält zum Beispiel alle fünf Nullen fest, selbst wenn die Genauigkeit des Kontexts nur drei beträgt.

Das Argument context legt fest, was geschieht, wenn value eine fehlerhafte Zeichenkette ist. Hat der Kontext einen Trap für InvalidOperation, wird eine Ausnahme ausgelöst. Andernfalls gibt der Konstruktor ein neues Decimal mit dem Wert NaN zurück.

Einmal erzeugt, sind Decimal-Objekte unveränderlich.

Geändert in Version 3.2: Das Argument des Konstruktors darf jetzt eine float-Instanz sein.

Geändert in Version 3.3: float-Argumente lösen eine Ausnahme aus, wenn der Trap für FloatOperation gesetzt ist. Voreingestellt ist er aus.

Geändert in Version 3.6: Unterstriche sind zur Gruppierung erlaubt, wie bei ganzzahligen und Gleitkommaliteralen im Code.

Dezimale Gleitkommaobjekte teilen viele Eigenschaften mit den anderen integrierten numerischen Typen wie float und int. Alle üblichen mathematischen Operationen und besonderen Methoden gelten. Ebenso lassen sich Decimal-Objekte kopieren, serialisieren, ausgeben, als Dictionary-Schlüssel und Mengenelemente verwenden, vergleichen, sortieren und in einen anderen Typ überführen, etwa in float oder int.

Zwischen der Arithmetik auf Decimal-Objekten und der auf ganzen Zahlen und Floats gibt es kleine Unterschiede. Wird der Restoperator % auf Decimal-Objekte angewendet, ist das Vorzeichen des Ergebnisses das Vorzeichen des Dividenden und nicht das des Divisors:

>>> (-7) % 4
1
>>> Decimal(-7) % Decimal(4)
Decimal('-3')

Der Operator für die Ganzzahldivision // verhält sich entsprechend: Er gibt den ganzzahligen Teil des echten Quotienten zurück – abgeschnitten in Richtung null – und nicht dessen Abrundung, damit die gewohnte Identität x == (x // y) * y + x % y erhalten bleibt:

>>> -7 // 4
-2
>>> Decimal(-7) // Decimal(4)
Decimal('-1')

Die Operatoren % und // setzen die Operationen remainder beziehungsweise divide-integer um, wie die Spezifikation sie beschreibt.

Decimal-Objekte lassen sich in arithmetischen Operationen im Allgemeinen nicht mit Floats oder Instanzen von fractions.Fraction verbinden: Der Versuch, ein Decimal zu einem float zu addieren, löst zum Beispiel einen TypeError aus. Mit Pythons Vergleichsoperatoren lässt sich aber eine Decimal-Instanz x mit einer anderen Zahl y vergleichen. Das vermeidet verwirrende Ergebnisse bei Gleichheitsvergleichen zwischen Zahlen verschiedener Typen.

Geändert in Version 3.2: Vergleiche gemischter Typen zwischen Decimal-Instanzen und anderen numerischen Typen werden jetzt vollständig unterstützt.

Neben den üblichen numerischen Eigenschaften haben dezimale Gleitkommaobjekte auch eine Reihe eigener Methoden:

adjusted()

Gibt den angepassten Exponenten zurück, nachdem die rechten Ziffern des Koeffizienten herausgeschoben wurden, bis nur die führende Ziffer übrig ist: Decimal('321e+5').adjusted() gibt sieben zurück. Dient dazu, die Stellung der höchstwertigen Ziffer zum Dezimaltrennzeichen zu bestimmen.

as_integer_ratio()

Gibt ein Paar (n, d) ganzer Zahlen zurück, das die gegebene Decimal-Instanz als Bruch darstellt, vollständig gekürzt und mit positivem Nenner:

>>> Decimal('-3.14').as_integer_ratio()
(-157, 50)

Die Umwandlung ist genau. Löst bei Unendlichkeiten OverflowError und bei NaNs ValueError aus.

Added in version 3.6.

as_tuple()

Gibt eine Darstellung der Zahl als benanntes Tupel zurück: DecimalTuple(sign, digits, exponent).

canonical()

Gibt die kanonische Kodierung des Arguments zurück. Derzeit ist die Kodierung einer Decimal-Instanz immer kanonisch, daher gibt diese Operation ihr Argument unverändert zurück.

compare(other, context=None)

Vergleicht die Werte zweier Decimal-Instanzen. compare() gibt eine Decimal-Instanz zurück. Ist einer der Operanden ein NaN, ist das Ergebnis ein NaN:

a or b is a NaN  ==> Decimal('NaN')
a < b            ==> Decimal('-1')
a == b           ==> Decimal('0')
a > b            ==> Decimal('1')
compare_signal(other, context=None)

Diese Operation ist gleichbedeutend mit der Methode compare(), nur dass alle NaNs signalisieren. Ist also keiner der Operanden ein signalisierendes NaN, wird jeder stille NaN-Operand behandelt, als wäre er ein signalisierendes NaN.

compare_total(other, context=None)

Vergleicht zwei Operanden anhand ihrer abstrakten Darstellung statt anhand ihres numerischen Werts. Ähnlich der Methode compare(), doch das Ergebnis ergibt eine Gesamtordnung auf Decimal-Instanzen. Zwei Decimal-Instanzen mit demselben numerischen Wert, aber verschiedener Darstellung gelten in dieser Ordnung als ungleich:

>>> Decimal('12.0').compare_total(Decimal('12'))
Decimal('-1')

Stille und signalisierende NaNs gehören ebenfalls zur Gesamtordnung. Das Ergebnis dieser Funktion ist Decimal('0'), wenn beide Operanden dieselbe Darstellung haben, Decimal('-1'), wenn der erste Operand in der Gesamtordnung niedriger steht als der zweite, und Decimal('1'), wenn der erste höher steht als der zweite. Einzelheiten zur Gesamtordnung stehen in der Spezifikation.

Diese Operation ist vom Kontext unberührt und still: Es werden keine Flags geändert und nicht gerundet. Als Ausnahme kann die C-Fassung InvalidOperation auslösen, wenn sich der zweite Operand nicht genau umwandeln lässt.

compare_total_mag(other, context=None)

Vergleicht zwei Operanden anhand ihrer abstrakten Darstellung statt anhand ihres Werts wie bei compare_total(), übergeht dabei aber das Vorzeichen beider Operanden. x.compare_total_mag(y) entspricht x.copy_abs().compare_total(y.copy_abs()).

Diese Operation ist vom Kontext unberührt und still: Es werden keine Flags geändert und nicht gerundet. Als Ausnahme kann die C-Fassung InvalidOperation auslösen, wenn sich der zweite Operand nicht genau umwandeln lässt.

conjugate()

Gibt einfach self zurück. Diese Methode gibt es nur, um der Decimal-Spezifikation zu entsprechen.

copy_abs()

Gibt den Absolutwert des Arguments zurück. Diese Operation ist vom Kontext unberührt und still: Es werden keine Flags geändert und nicht gerundet.

copy_negate()

Gibt die Negation des Arguments zurück. Diese Operation ist vom Kontext unberührt und still: Es werden keine Flags geändert und nicht gerundet.

copy_sign(other, context=None)

Gibt eine Kopie des ersten Operanden zurück, deren Vorzeichen auf das des zweiten Operanden gesetzt ist. Zum Beispiel:

>>> Decimal('2.3').copy_sign(Decimal('-1.5'))
Decimal('-2.3')

Diese Operation ist vom Kontext unberührt und still: Es werden keine Flags geändert und nicht gerundet. Als Ausnahme kann die C-Fassung InvalidOperation auslösen, wenn sich der zweite Operand nicht genau umwandeln lässt.

exp(context=None)

Gibt den Wert der (natürlichen) Exponentialfunktion e**x an der gegebenen Zahl zurück. Das Ergebnis ist mit dem Rundungsmodus ROUND_HALF_EVEN korrekt gerundet.

>>> Decimal(1).exp()
Decimal('2.718281828459045235360287471')
>>> Decimal(321).exp()
Decimal('2.561702493119680037517373933E+139')
classmethod from_float(f, /)

Weiterer Konstruktor, der nur Instanzen von float oder int annimmt.

Beachte: Decimal.from_float(0.1) ist nicht dasselbe wie Decimal('0.1'). Da 0.1 im binären Gleitkomma nicht genau darstellbar ist, wird der Wert als nächstgelegener darstellbarer Wert gespeichert, nämlich 0x1.999999999999ap-4. Dezimal entspricht das 0.1000000000000000055511151231257827021181583404541015625.

Bemerkung

Seit Python 3.2 lässt sich eine Decimal-Instanz auch unmittelbar aus einem float erzeugen.

>>> Decimal.from_float(0.1)
Decimal('0.1000000000000000055511151231257827021181583404541015625')
>>> Decimal.from_float(float('nan'))
Decimal('NaN')
>>> Decimal.from_float(float('inf'))
Decimal('Infinity')
>>> Decimal.from_float(float('-inf'))
Decimal('-Infinity')

Added in version 3.1.

classmethod from_number(number, /)

Weiterer Konstruktor, der nur Instanzen von float, int oder Decimal annimmt, aber keine Zeichenketten und Tupel.

>>> Decimal.from_number(314)
Decimal('314')
>>> Decimal.from_number(0.1)
Decimal('0.1000000000000000055511151231257827021181583404541015625')
>>> Decimal.from_number(Decimal('3.14'))
Decimal('3.14')

Added in version 3.14.

fma(other, third, context=None)

Verschmolzene Multiplikation und Addition. Gibt self*other+third zurück, ohne das Zwischenprodukt self*other zu runden.

>>> Decimal(2).fma(3, 5)
Decimal('11')
is_canonical()

Gibt True zurück, wenn das Argument kanonisch ist, sonst False. Derzeit ist eine Decimal-Instanz immer kanonisch, daher gibt diese Operation immer True zurück.

is_finite()

Gibt True zurück, wenn das Argument eine endliche Zahl ist, und False, wenn es eine Unendlichkeit oder ein NaN ist.

is_infinite()

Gibt True zurück, wenn das Argument positive oder negative Unendlichkeit ist, sonst False.

is_nan()

Gibt True zurück, wenn das Argument ein (stilles oder signalisierendes) NaN ist, sonst False.

is_normal(context=None)

Gibt True zurück, wenn das Argument eine normale endliche Zahl ist. Gibt False zurück, wenn das Argument null, subnormal, unendlich oder ein NaN ist.

is_qnan()

Gibt True zurück, wenn das Argument ein stilles NaN ist, sonst False.

is_signed()

Gibt True zurück, wenn das Argument ein negatives Vorzeichen hat, sonst False. Beachte, dass sowohl Nullen als auch NaNs Vorzeichen tragen können.

is_snan()

Gibt True zurück, wenn das Argument ein signalisierendes NaN ist, sonst False.

is_subnormal(context=None)

Gibt True zurück, wenn das Argument subnormal ist, sonst False.

is_zero()

Gibt True zurück, wenn das Argument eine (positive oder negative) Null ist, sonst False.

ln(context=None)

Gibt den natürlichen Logarithmus des Operanden zur Basis e zurück. Das Ergebnis ist mit dem Rundungsmodus ROUND_HALF_EVEN korrekt gerundet.

log10(context=None)

Gibt den Logarithmus des Operanden zur Basis zehn zurück. Das Ergebnis ist mit dem Rundungsmodus ROUND_HALF_EVEN korrekt gerundet.

logb(context=None)

Gibt bei einer Zahl ungleich null den angepassten Exponenten ihres Operanden als Decimal-Instanz zurück. Ist der Operand null, wird Decimal('-Infinity') zurückgegeben und das Flag DivisionByZero gesetzt. Ist der Operand eine Unendlichkeit, wird Decimal('Infinity') zurückgegeben.

logical_and(other, context=None)

logical_and() ist eine logische Operation mit zwei logischen Operanden (siehe Logische Operanden). Das Ergebnis ist das ziffernweise and der beiden Operanden.

logical_invert(context=None)

logical_invert() ist eine logische Operation. Das Ergebnis ist die ziffernweise Umkehrung des Operanden.

logical_or(other, context=None)

logical_or() ist eine logische Operation mit zwei logischen Operanden (siehe Logische Operanden). Das Ergebnis ist das ziffernweise or der beiden Operanden.

logical_xor(other, context=None)

logical_xor() ist eine logische Operation mit zwei logischen Operanden (siehe Logische Operanden). Das Ergebnis ist das ziffernweise exklusive Oder der beiden Operanden.

max(other, context=None)

Wie max(self, other), nur wird vor der Rückgabe die Rundungsregel des Kontexts angewendet und NaN-Werte werden entweder signalisiert oder übergangen – je nach Kontext und je nachdem, ob sie signalisierend oder still sind.

max_mag(other, context=None)

Ähnlich der Methode max(), der Vergleich erfolgt aber anhand der Absolutwerte der Operanden.

min(other, context=None)

Wie min(self, other), nur wird vor der Rückgabe die Rundungsregel des Kontexts angewendet und NaN-Werte werden entweder signalisiert oder übergangen – je nach Kontext und je nachdem, ob sie signalisierend oder still sind.

min_mag(other, context=None)

Ähnlich der Methode min(), der Vergleich erfolgt aber anhand der Absolutwerte der Operanden.

next_minus(context=None)

Gibt die größte im gegebenen Kontext darstellbare Zahl zurück – oder im Kontext des aktuellen Threads, wenn kein Kontext angegeben ist –, die kleiner ist als der gegebene Operand.

next_plus(context=None)

Gibt die kleinste im gegebenen Kontext darstellbare Zahl zurück – oder im Kontext des aktuellen Threads, wenn kein Kontext angegeben ist –, die größer ist als der gegebene Operand.

next_toward(other, context=None)

Sind die beiden Operanden ungleich, wird die Zahl zurückgegeben, die dem ersten Operanden in Richtung des zweiten am nächsten liegt. Sind beide Operanden numerisch gleich, wird eine Kopie des ersten Operanden zurückgegeben, deren Vorzeichen auf das des zweiten gesetzt ist.

normalize(context=None)

Dient dazu, kanonische Werte einer Äquivalenzklasse zu erzeugen, entweder im aktuellen oder im angegebenen Kontext.

Das hat dieselbe Bedeutung wie der einstellige Plus-Operator, nur wird ein endliches Endergebnis auf seine einfachste Form gebracht: Alle abschließenden Nullen werden entfernt, das Vorzeichen bleibt erhalten. Solange der Koeffizient also ungleich null und ein Vielfaches von zehn ist, wird er durch zehn geteilt und der Exponent um 1 erhöht. Andernfalls – der Koeffizient ist null – wird der Exponent auf 0 gesetzt. In allen Fällen bleibt das Vorzeichen unverändert.

Decimal('32.100') und Decimal('0.321000e+2') normalisieren zum Beispiel beide zum gleichwertigen Wert Decimal('32.1').

Beachte, dass vor dem Bringen auf die einfachste Form gerundet wird.

In den neuesten Fassungen der Spezifikation heißt diese Operation auch reduce.

number_class(context=None)

Gibt eine Zeichenkette zurück, die die Klasse des Operanden beschreibt. Der zurückgegebene Wert ist eine der folgenden zehn Zeichenketten.

  • "-Infinity" – der Operand ist negative Unendlichkeit.

  • "-Normal" – der Operand ist eine negative normale Zahl.

  • "-Subnormal" – der Operand ist negativ und subnormal.

  • "-Zero" – der Operand ist eine negative Null.

  • "+Zero" – der Operand ist eine positive Null.

  • "+Subnormal" – der Operand ist positiv und subnormal.

  • "+Normal" – der Operand ist eine positive normale Zahl.

  • "+Infinity" – der Operand ist positive Unendlichkeit.

  • "NaN" – der Operand ist ein stilles NaN (Not a Number).

  • "sNaN" – der Operand ist ein signalisierendes NaN.

quantize(exp, rounding=None, context=None)

Gibt einen Wert zurück, der nach dem Runden dem ersten Operanden gleicht und den Exponenten des zweiten Operanden hat.

>>> Decimal('1.41421356').quantize(Decimal('1.000'))
Decimal('1.414')

Anders als bei anderen Operationen wird ein InvalidOperation signalisiert, wenn die Länge des Koeffizienten nach der quantize-Operation größer als die Genauigkeit wäre. Das garantiert, dass der quantisierte Exponent – außer bei einem Fehlerzustand – immer dem des rechten Operanden gleicht.

Ebenfalls anders als andere Operationen signalisiert quantize nie Underflow, selbst wenn das Ergebnis subnormal und ungenau ist.

Ist der Exponent des zweiten Operanden größer als der des ersten, kann Runden nötig sein. Dann bestimmt das Argument rounding den Rundungsmodus, sofern angegeben, sonst das Argument context. Ist keines von beiden angegeben, wird der Rundungsmodus des Kontexts des aktuellen Threads verwendet.

Ein Fehler wird zurückgegeben, sobald der entstehende Exponent größer als Emax oder kleiner als Etiny() ist.

radix()

Gibt Decimal(10) zurück, den Radix – die Basis –, in dem die Klasse Decimal ihre gesamte Arithmetik betreibt. Aus Kompatibilität mit der Spezifikation enthalten.

remainder_near(other, context=None)

Gibt den Rest der Division von self durch other zurück. Anders als bei self % other wird das Vorzeichen des Restes so gewählt, dass sein Absolutwert möglichst klein ist. Genauer ist der Rückgabewert self - n * other, wobei n die ganze Zahl ist, die dem genauen Wert von self / other am nächsten liegt. Liegen zwei ganze Zahlen gleich nah, wird die gerade gewählt.

Ist das Ergebnis null, ist sein Vorzeichen das von self.

>>> Decimal(18).remainder_near(Decimal(10))
Decimal('-2')
>>> Decimal(25).remainder_near(Decimal(10))
Decimal('5')
>>> Decimal(35).remainder_near(Decimal(10))
Decimal('-5')
rotate(other, context=None)

Gibt das Ergebnis zurück, wenn die Ziffern des ersten Operanden um den vom zweiten Operanden angegebenen Betrag rotiert werden. Der zweite Operand muss eine ganze Zahl im Bereich von minus Genauigkeit bis Genauigkeit sein. Sein Absolutwert gibt die Anzahl der Stellen an, um die rotiert wird. Ist der zweite Operand positiv, wird nach links rotiert, sonst nach rechts. Der Koeffizient des ersten Operanden wird bei Bedarf links mit Nullen auf die Länge der Genauigkeit aufgefüllt. Vorzeichen und Exponent des ersten Operanden bleiben unverändert.

same_quantum(other, context=None)

Prüft, ob self und other denselben Exponenten haben oder ob beide NaN sind.

Diese Operation ist vom Kontext unberührt und still: Es werden keine Flags geändert und nicht gerundet. Als Ausnahme kann die C-Fassung InvalidOperation auslösen, wenn sich der zweite Operand nicht genau umwandeln lässt.

scaleb(other, context=None)

Gibt den ersten Operanden mit um den zweiten angepasstem Exponenten zurück, also den ersten Operanden multipliziert mit 10**other. Der zweite Operand muss eine ganze Zahl sein.

shift(other, context=None)

Gibt das Ergebnis zurück, wenn die Ziffern des ersten Operanden um den vom zweiten Operanden angegebenen Betrag verschoben werden. Der zweite Operand muss eine ganze Zahl im Bereich von minus Genauigkeit bis Genauigkeit sein. Sein Absolutwert gibt die Anzahl der Stellen an, um die verschoben wird. Ist der zweite Operand positiv, wird nach links verschoben, sonst nach rechts. Die in den Koeffizienten hineingeschobenen Ziffern sind Nullen. Vorzeichen und Exponent des ersten Operanden bleiben unverändert.

sqrt(context=None)

Gibt die Quadratwurzel des Arguments mit voller Genauigkeit zurück.

to_eng_string(context=None)

Wandelt in eine Zeichenkette um. Wird ein Exponent gebraucht, wird die technische Schreibweise verwendet.

Die technische Schreibweise hat einen Exponenten, der ein Vielfaches von 3 ist. Dadurch können bis zu 3 Ziffern links vom Dezimaltrennzeichen stehen und es kann nötig sein, eine oder zwei abschließende Nullen anzufügen.

So wird zum Beispiel Decimal('123E+1') zu Decimal('1.23E+3').

to_integral(rounding=None, context=None)

Gleichbedeutend mit der Methode to_integral_value(). Der Name to_integral bleibt aus Kompatibilität mit älteren Versionen erhalten.

to_integral_exact(rounding=None, context=None)

Rundet auf die nächste ganze Zahl und signalisiert Inexact oder Rounded, wie es beim Runden angemessen ist. Den Rundungsmodus bestimmt der Parameter rounding, sofern angegeben, sonst das angegebene context. Ist keiner von beiden angegeben, wird der Rundungsmodus des aktuellen Kontexts verwendet.

to_integral_value(rounding=None, context=None)

Rundet auf die nächste ganze Zahl, ohne Inexact oder Rounded zu signalisieren. Wendet rounding an, sofern angegeben. Sonst wird der Rundungsmodus des übergebenen context oder des aktuellen Kontexts verwendet.

Dezimalzahlen lassen sich mit der Funktion round() runden:

round(number)
round(number, ndigits)

Ist ndigits nicht angegeben oder None, wird der number nächstgelegene int zurückgegeben, wobei Gleichstände zur geraden Zahl gerundet werden und der Rundungsmodus des Decimal-Kontexts übergangen wird. Löst OverflowError aus, wenn number eine Unendlichkeit ist, oder ValueError, wenn es ein (stilles oder signalisierendes) NaN ist.

Ist ndigits ein int, wird der Rundungsmodus des Kontexts beachtet und ein Decimal zurückgegeben, das number auf das nächste Vielfache von Decimal('1E-ndigits') gerundet darstellt. In diesem Fall entspricht round(number, ndigits) dem Aufruf self.quantize(Decimal('1E-ndigits')). Gibt Decimal('NaN') zurück, wenn number ein stilles NaN ist. Löst InvalidOperation aus, wenn number eine Unendlichkeit oder ein signalisierendes NaN ist oder wenn die Länge des Koeffizienten nach der quantize-Operation größer wäre als die Genauigkeit des aktuellen Kontexts. Mit anderen Worten, abgesehen von den Randfällen:

  • ist ndigits positiv, wird number auf ndigits Dezimalstellen gerundet zurückgegeben;

  • ist ndigits null, wird number auf die nächste ganze Zahl gerundet zurückgegeben;

  • ist ndigits negativ, wird number auf das nächste Vielfache von 10**abs(ndigits) gerundet zurückgegeben.

Zum Beispiel:

>>> from decimal import Decimal, getcontext, ROUND_DOWN
>>> getcontext().rounding = ROUND_DOWN
>>> round(Decimal('3.75'))     # context rounding ignored
4
>>> round(Decimal('3.5'))      # round-ties-to-even
4
>>> round(Decimal('3.75'), 0)  # uses the context rounding
Decimal('3')
>>> round(Decimal('3.75'), 1)
Decimal('3.7')
>>> round(Decimal('3.75'), -1)
Decimal('0E+1')

Logische Operanden

Die Methoden logical_and(), logical_invert(), logical_or() und logical_xor() erwarten als Argumente logische Operanden. Ein logischer Operand ist eine Decimal-Instanz, deren Exponent und Vorzeichen beide null sind und deren Ziffern alle 0 oder 1 sind.

Context-Objekte

Kontexte sind Umgebungen für arithmetische Operationen. Sie bestimmen die Genauigkeit, legen Regeln für die Rundung fest, entscheiden, welche Signale als Ausnahmen behandelt werden, und begrenzen den Bereich der Exponenten.

Jeder Thread hat seinen eigenen aktuellen Kontext, auf den die Funktionen getcontext() und setcontext() zugreifen beziehungsweise den sie ändern:

decimal.getcontext()

Gibt den aktuellen Kontext des aktiven Threads zurück.

decimal.setcontext(c, /)

Setzt den aktuellen Kontext des aktiven Threads auf c.

Mit der with-Anweisung und der Funktion localcontext() lässt sich der aktive Kontext auch vorübergehend ändern.

decimal.localcontext(ctx=None, **kwargs)

Gibt einen Kontextmanager zurück, der beim Eintritt in die with-Anweisung den aktuellen Kontext des aktiven Threads auf eine Kopie von ctx setzt und beim Verlassen den vorherigen Kontext wiederherstellt. Ist kein Kontext angegeben, wird eine Kopie des aktuellen Kontexts verwendet. Das Argument kwargs dient dazu, die Attribute des neuen Kontexts zu setzen.

Der folgende Code setzt die aktuelle Dezimalgenauigkeit zum Beispiel auf 42 Stellen, führt eine Rechnung aus und stellt dann selbsttätig den vorherigen Kontext wieder her:

from decimal import localcontext

with localcontext() as ctx:
    ctx.prec = 42   # Perform a high precision calculation
    s = calculate_something()
s = +s  # Round the final result back to the default precision

Mit Schlüsselwortargumenten sähe der Code so aus:

from decimal import localcontext

with localcontext(prec=42) as ctx:
    s = calculate_something()
s = +s

Löst TypeError aus, wenn kwargs ein Attribut liefert, das Context nicht unterstützt. Löst TypeError oder ValueError aus, wenn kwargs einen ungültigen Wert für ein Attribut liefert.

Geändert in Version 3.11: localcontext() unterstützt es jetzt, Kontextattribute über Schlüsselwortargumente zu setzen.

decimal.IEEEContext(bits)

Gibt ein Kontextobjekt zurück, das mit den passenden Werten für eines der IEEE-Austauschformate initialisiert ist. Das Argument muss ein Vielfaches von 32 und kleiner als IEEE_CONTEXT_MAX_BITS sein.

Added in version 3.14.

Neue Kontexte lassen sich auch mit dem unten beschriebenen Konstruktor Context erzeugen. Außerdem stellt das Modul drei vorgefertigte Kontexte bereit:

decimal.BasicContext

Ein Standardkontext, den die General Decimal Arithmetic Specification festlegt. Die Genauigkeit steht auf neun, die Rundung auf ROUND_HALF_UP. Alle Flags sind geleert. Alle Traps sind eingeschaltet, werden also als Ausnahmen behandelt, außer Inexact, Rounded und Subnormal.

Da viele der Traps eingeschaltet sind, ist dieser Kontext zur Fehlersuche nützlich.

decimal.ExtendedContext

Ein Standardkontext, den die General Decimal Arithmetic Specification festlegt. Die Genauigkeit steht auf neun, die Rundung auf ROUND_HALF_EVEN. Alle Flags sind geleert. Keine Traps sind eingeschaltet, sodass während der Rechnungen keine Ausnahmen ausgelöst werden.

Da die Traps abgeschaltet sind, ist dieser Kontext für Anwendungen nützlich, denen ein Ergebnis von NaN oder Infinity lieber ist als eine ausgelöste Ausnahme. So kann eine Anwendung einen Lauf auch bei Zuständen abschließen, die das Programm sonst anhalten würden.

decimal.DefaultContext

Diesen Kontext verwendet der Konstruktor Context als Vorlage für neue Kontexte. Ein Feld zu ändern – etwa die Genauigkeit – ändert damit die Voreinstellung für neue Kontexte, die der Konstruktor Context erzeugt.

Am nützlichsten ist dieser Kontext in Umgebungen mit mehreren Threads. Ändert man eines der Felder, bevor Threads gestartet werden, setzt man damit systemweite Voreinstellungen. Die Felder nach dem Start von Threads zu ändern ist nicht empfehlenswert, denn dann wäre eine Synchronisierung der Threads nötig, um Wettlaufsituationen zu vermeiden.

In Umgebungen mit einem einzigen Thread ist es besser, diesen Kontext gar nicht zu verwenden, sondern Kontexte einfach ausdrücklich zu erzeugen, wie unten beschrieben.

Die voreingestellten Werte sind Context.prec=28, Context.rounding=ROUND_HALF_EVEN sowie eingeschaltete Traps für Overflow, InvalidOperation und DivisionByZero.

Neben den drei mitgelieferten Kontexten lassen sich mit dem Konstruktor Context neue Kontexte erzeugen.

class decimal.Context(prec=None, rounding=None, Emin=None, Emax=None, capitals=None, clamp=None, flags=None, traps=None)

Erzeugt einen neuen Kontext. Ist ein Feld nicht angegeben oder None, werden die voreingestellten Werte aus DefaultContext kopiert. Ist das Feld flags nicht angegeben oder None, werden alle Flags geleert.

prec

Eine ganze Zahl im Bereich [1, MAX_PREC], die die Genauigkeit für arithmetische Operationen im Kontext festlegt.

rounding

Eine der Konstanten aus dem Abschnitt Rounding Modes.

traps
flags

Listen der zu setzenden Signale. Im Allgemeinen sollten neue Kontexte nur Traps setzen und die Flags geleert lassen.

Emin
Emax

Ganze Zahlen, die die äußeren erlaubten Grenzen für Exponenten angeben. Emin muss im Bereich [MIN_EMIN, 0] liegen, Emax im Bereich [0, MAX_EMAX].

capitals

Entweder 0 oder 1 (die Voreinstellung). Steht der Wert auf 1, werden Exponenten mit großem E ausgegeben, sonst mit kleinem e: Decimal('6.02e+23').

clamp

Entweder 0 (die Voreinstellung) oder 1. Steht der Wert auf 1, ist der Exponent e einer in diesem Kontext darstellbaren Decimal-Instanz streng auf den Bereich Emin - prec + 1 <= e <= Emax - prec + 1 begrenzt. Ist clamp 0, gilt eine schwächere Bedingung: Der angepasste Exponent der Decimal-Instanz ist höchstens Emax. Ist clamp 1, wird bei einer großen normalen Zahl, wo möglich, der Exponent verkleinert und dem Koeffizienten eine entsprechende Anzahl Nullen hinzugefügt, damit sie in die Grenzen des Exponenten passt. Das erhält den Wert der Zahl, verliert aber die Information über signifikante abschließende Nullen. Zum Beispiel:

>>> Context(prec=6, Emax=999, clamp=1).create_decimal('1.23e999')
Decimal('1.23000E+999')

Ein clamp-Wert von 1 ermöglicht die Kompatibilität mit den dezimalen Austauschformaten fester Breite, die IEEE 754 festlegt.

Die Klasse Context definiert mehrere Methoden für allgemeine Zwecke sowie eine große Zahl von Methoden, um unmittelbar in einem gegebenen Kontext zu rechnen. Außerdem gibt es zu jeder der oben beschriebenen Decimal-Methoden – mit Ausnahme von adjusted() und as_tuple() – eine entsprechende Context-Methode. Für eine Context-Instanz C und eine Decimal-Instanz x entspricht zum Beispiel C.exp(x) dem Aufruf x.exp(context=C). Jede Context-Methode nimmt überall dort, wo eine Decimal-Instanz zulässig ist, auch eine ganze Python-Zahl an, also eine Instanz von int.

clear_flags()

Setzt alle Flags auf 0 zurück.

clear_traps()

Setzt alle Traps auf 0 zurück.

Added in version 3.3.

copy()

Gibt ein Duplikat des Kontexts zurück.

copy_decimal(num, /)

Gibt eine Kopie der Decimal-Instanz num zurück.

create_decimal(num='0', /)

Erzeugt eine neue Decimal-Instanz aus num, verwendet aber self als Kontext. Anders als beim Konstruktor Decimal werden Genauigkeit, Rundungsmethode, Flags und Traps des Kontexts auf die Umwandlung angewendet.

Das ist nützlich, weil Konstanten oft mit größerer Genauigkeit angegeben werden, als die Anwendung braucht. Ein weiterer Vorteil: Das sofortige Runden beseitigt unbeabsichtigte Auswirkungen von Ziffern jenseits der aktuellen Genauigkeit. Im folgenden Beispiel führen ungerundete Eingaben dazu, dass das Addieren von null zu einer Summe das Ergebnis ändern kann:

>>> getcontext().prec = 3
>>> Decimal('3.4445') + Decimal('1.0023')
Decimal('4.45')
>>> Decimal('3.4445') + Decimal(0) + Decimal('1.0023')
Decimal('4.44')

Diese Methode setzt die to-number-Operation der IBM-Spezifikation um. Ist das Argument eine Zeichenkette, sind Leerraum und Unterstriche am Anfang und Ende nicht erlaubt.

create_decimal_from_float(f, /)

Erzeugt eine neue Decimal-Instanz aus einem Float f, rundet aber mit self als Kontext. Anders als bei der Klassenmethode Decimal.from_float() werden Genauigkeit, Rundungsmethode, Flags und Traps des Kontexts auf die Umwandlung angewendet.

>>> context = Context(prec=5, rounding=ROUND_DOWN)
>>> context.create_decimal_from_float(math.pi)
Decimal('3.1415')
>>> context = Context(prec=5, traps=[Inexact])
>>> context.create_decimal_from_float(math.pi)
Traceback (most recent call last):
    ...
decimal.Inexact: None

Added in version 3.1.

Etiny()

Gibt einen Wert gleich Emin - prec + 1 zurück, den kleinsten Exponentenwert für subnormale Ergebnisse. Tritt ein Unterlauf auf, wird der Exponent auf Etiny gesetzt.

Etop()

Gibt einen Wert gleich Emax - prec + 1 zurück.

Üblicherweise arbeitet man mit Decimals so, dass man Decimal-Instanzen erzeugt und dann arithmetische Operationen anwendet, die im aktuellen Kontext des aktiven Threads stattfinden. Alternativ lässt sich mit Kontextmethoden in einem bestimmten Kontext rechnen. Die Methoden gleichen denen der Klasse Decimal und sind hier nur kurz aufgeführt.

abs(x, /)

Gibt den Absolutwert von x zurück.

add(x, y, /)

Gibt die Summe von x und y zurück.

canonical(x, /)

Gibt dasselbe Decimal-Objekt x zurück.

compare(x, y, /)

Vergleicht x und y numerisch.

compare_signal(x, y, /)

Vergleicht die Werte der beiden Operanden numerisch.

compare_total(x, y, /)

Vergleicht zwei Operanden anhand ihrer abstrakten Darstellung.

compare_total_mag(x, y, /)

Vergleicht zwei Operanden anhand ihrer abstrakten Darstellung und übergeht das Vorzeichen.

copy_abs(x, /)

Gibt eine Kopie von x zurück, deren Vorzeichen auf 0 gesetzt ist.

copy_negate(x, /)

Gibt eine Kopie von x mit umgekehrtem Vorzeichen zurück.

copy_sign(x, y, /)

Kopiert das Vorzeichen von y nach x.

divide(x, y, /)

Gibt x geteilt durch y zurück.

divide_int(x, y, /)

Gibt x geteilt durch y zurück, auf eine ganze Zahl abgeschnitten.

divmod(x, y, /)

Teilt zwei Zahlen und gibt den ganzzahligen Teil des Ergebnisses zurück.

exp(x, /)

Gibt e ** x zurück.

fma(x, y, z, /)

Gibt x multipliziert mit y, plus z zurück.

is_canonical(x, /)

Gibt True zurück, wenn x kanonisch ist, sonst False.

is_finite(x, /)

Gibt True zurück, wenn x endlich ist, sonst False.

is_infinite(x, /)

Gibt True zurück, wenn x unendlich ist, sonst False.

is_nan(x, /)

Gibt True zurück, wenn x ein qNaN oder sNaN ist, sonst False.

is_normal(x, /)

Gibt True zurück, wenn x eine normale Zahl ist, sonst False.

is_qnan(x, /)

Gibt True zurück, wenn x ein stilles NaN ist, sonst False.

is_signed(x, /)

Gibt True zurück, wenn x negativ ist, sonst False.

is_snan(x, /)

Gibt True zurück, wenn x ein signalisierendes NaN ist, sonst False.

is_subnormal(x, /)

Gibt True zurück, wenn x subnormal ist, sonst False.

is_zero(x, /)

Gibt True zurück, wenn x eine Null ist, sonst False.

ln(x, /)

Gibt den natürlichen Logarithmus von x zur Basis e zurück.

log10(x, /)

Gibt den Logarithmus von x zur Basis 10 zurück.

logb(x, /)

Gibt den Exponenten des Betrags der höchstwertigen Ziffer des Operanden zurück.

logical_and(x, y, /)

Wendet die logische Operation and auf die Ziffern der Operanden an.

logical_invert(x, /)

Kehrt alle Ziffern in x um.

logical_or(x, y, /)

Wendet die logische Operation or auf die Ziffern der Operanden an.

logical_xor(x, y, /)

Wendet die logische Operation xor auf die Ziffern der Operanden an.

max(x, y, /)

Vergleicht zwei Werte numerisch und gibt den größeren zurück.

max_mag(x, y, /)

Vergleicht die Werte numerisch und übergeht ihr Vorzeichen.

min(x, y, /)

Vergleicht zwei Werte numerisch und gibt den kleineren zurück.

min_mag(x, y, /)

Vergleicht die Werte numerisch und übergeht ihr Vorzeichen.

minus(x, /)

Minus entspricht dem einstelligen vorangestellten Minus-Operator in Python.

multiply(x, y, /)

Gibt das Produkt von x und y zurück.

next_minus(x, /)

Gibt die größte darstellbare Zahl zurück, die kleiner ist als x.

next_plus(x, /)

Gibt die kleinste darstellbare Zahl zurück, die größer ist als x.

next_toward(x, y, /)

Gibt die Zahl zurück, die x in Richtung y am nächsten liegt.

normalize(x, /)

Bringt x auf seine einfachste Form.

number_class(x, /)

Gibt eine Angabe zur Klasse von x zurück.

plus(x, /)

Plus entspricht dem einstelligen vorangestellten Plus-Operator in Python. Diese Operation wendet Genauigkeit und Rundung des Kontexts an, ist also keine Identitätsoperation.

power(x, y, modulo=None)

Gibt x hoch y zurück, modulo modulo reduziert, sofern angegeben.

Mit zwei Argumenten wird x**y berechnet. Ist x negativ, muss y ganzzahlig sein. Das Ergebnis ist ungenau, es sei denn, y ist ganzzahlig und das Ergebnis ist endlich und lässt sich genau in „precision“ Ziffern ausdrücken. Der Rundungsmodus des Kontexts wird verwendet. In der Python-Fassung sind die Ergebnisse immer korrekt gerundet.

Decimal(0) ** Decimal(0) ergibt InvalidOperation. Ist InvalidOperation nicht als Trap gesetzt, ergibt es Decimal('NaN').

Geändert in Version 3.3: Das C-Modul berechnet power() über die korrekt gerundeten Funktionen exp() und ln(). Das Ergebnis ist wohldefiniert, aber nur „fast immer korrekt gerundet“.

Mit drei Argumenten wird (x**y) % modulo berechnet. Für die Form mit drei Argumenten gelten die folgenden Einschränkungen:

  • alle drei Argumente müssen ganzzahlig sein

  • y muss nicht negativ sein

  • mindestens eines von x und y muss ungleich null sein

  • modulo muss ungleich null sein und höchstens „precision“ Ziffern haben

Der Wert aus Context.power(x, y, modulo) gleicht dem Wert, den (x**y) % modulo mit unbegrenzter Genauigkeit ergäbe, wird aber effizienter berechnet. Der Exponent des Ergebnisses ist null, unabhängig von den Exponenten von x, y und modulo. Das Ergebnis ist immer genau.

quantize(x, y, /)

Gibt einen Wert zurück, der dem gerundeten x gleicht und den Exponenten von y hat.

radix()

Gibt einfach 10 zurück, denn das hier ist Decimal :)

remainder(x, y, /)

Gibt den Rest der Ganzzahldivision zurück.

Das Vorzeichen des Ergebnisses ist, wenn es ungleich null ist, dasselbe wie das des ursprünglichen Dividenden.

remainder_near(x, y, /)

Gibt x - y * n zurück, wobei n die ganze Zahl ist, die dem genauen Wert von x / y am nächsten liegt. Ist das Ergebnis 0, ist sein Vorzeichen das von x.

rotate(x, y, /)

Gibt eine um y Stellen rotierte Kopie von x zurück.

same_quantum(x, y, /)

Gibt True zurück, wenn die beiden Operanden denselben Exponenten haben.

scaleb(x, y, /)

Gibt den ersten Operanden zurück, nachdem der zweite Wert zu seinem Exponenten addiert wurde.

shift(x, y, /)

Gibt eine um y Stellen verschobene Kopie von x zurück.

sqrt(x, /)

Quadratwurzel einer nicht negativen Zahl mit der Genauigkeit des Kontexts.

subtract(x, y, /)

Gibt die Differenz von x und y zurück.

to_eng_string(x, /)

Wandelt in eine Zeichenkette um. Wird ein Exponent gebraucht, wird die technische Schreibweise verwendet.

Die technische Schreibweise hat einen Exponenten, der ein Vielfaches von 3 ist. Dadurch können bis zu 3 Ziffern links vom Dezimaltrennzeichen stehen und es kann nötig sein, eine oder zwei abschließende Nullen anzufügen.

to_integral_exact(x, /)

Rundet auf eine ganze Zahl.

to_sci_string(x, /)

Wandelt eine Zahl in wissenschaftlicher Schreibweise in eine Zeichenkette um.

Konstanten

decimal.SPEC_VERSION

Die höchste Fassung der General Decimal Arithmetic Specification, der diese Umsetzung entspricht. Die Spezifikation steht unter https://speleotrove.com/decimal/decarith.html.

Added in version 3.15.

Die folgenden Konstanten sind nur für das C-Modul von Bedeutung. Aus Kompatibilität sind sie auch in der reinen Python-Fassung enthalten.

32-bit

64-bit

decimal.MAX_PREC

425000000

999999999999999999

decimal.MAX_EMAX

425000000

999999999999999999

decimal.MIN_EMIN

-425000000

-999999999999999999

decimal.MIN_ETINY

-849999999

-1999999999999999997

decimal.IEEE_CONTEXT_MAX_BITS

256

512

decimal.HAVE_THREADS

Der Wert ist True. Veraltet, weil Python jetzt immer Threads hat.

Veraltet ab Version 3.9.

decimal.HAVE_CONTEXTVAR

Der voreingestellte Wert ist True. Ist Python mit der Option --without-decimal-contextvar konfiguriert, verwendet die C-Fassung einen Kontext je Thread statt je Coroutine und der Wert ist False. In manchen Szenarien mit verschachtelten Kontexten ist das etwas schneller.

Added in version 3.8.3.

Rundungsmodi

decimal.ROUND_CEILING

Rundet in Richtung Infinity.

decimal.ROUND_DOWN

Rundet in Richtung null.

decimal.ROUND_FLOOR

Rundet in Richtung -Infinity.

decimal.ROUND_HALF_DOWN

Rundet zum nächsten Wert, bei Gleichstand in Richtung null.

decimal.ROUND_HALF_EVEN

Rundet zum nächsten Wert, bei Gleichstand zur nächsten geraden ganzen Zahl.

decimal.ROUND_HALF_UP

Rundet zum nächsten Wert, bei Gleichstand weg von null.

decimal.ROUND_UP

Rundet weg von null.

decimal.ROUND_05UP

Rundet weg von null, wenn die letzte Ziffer nach dem Runden in Richtung null 0 oder 5 gewesen wäre, sonst in Richtung null.

Signale

Signale stehen für Zustände, die während einer Rechnung auftreten. Zu jedem gehören ein Flag und ein Trap-Schalter des Kontexts.

Das Flag des Kontexts wird gesetzt, sobald der Zustand auftritt. Nach der Rechnung lassen sich die Flags zur Information prüfen, etwa um festzustellen, ob eine Rechnung genau war. Leere nach dem Prüfen unbedingt alle Flags, bevor du die nächste Rechnung beginnst.

Ist der Trap-Schalter des Kontexts für das Signal gesetzt, löst der Zustand eine Python-Ausnahme aus. Ist zum Beispiel der Trap für DivisionByZero gesetzt, wird beim Auftreten des Zustands eine DivisionByZero-Ausnahme ausgelöst.

class decimal.Clamped

Ein Exponent wurde geändert, um in die Grenzen der Darstellung zu passen.

Üblicherweise tritt Clamping auf, wenn ein Exponent außerhalb der Grenzen Emin und Emax des Kontexts liegt. Wenn möglich, wird der Exponent passend verkleinert, indem dem Koeffizienten Nullen hinzugefügt werden.

class decimal.DecimalException

Basisklasse für die anderen Signale und Unterklasse von ArithmeticError.

class decimal.DivisionByZero

Signalisiert die Division einer nicht unendlichen Zahl durch null.

Kann bei der Division, der Modulo-Division oder beim Potenzieren einer Zahl mit einem negativen Exponenten auftreten. Ist dieses Signal nicht als Trap gesetzt, wird Infinity oder -Infinity zurückgegeben. Das Vorzeichen bestimmen die Eingaben der Rechnung.

class decimal.Inexact

Zeigt an, dass gerundet wurde und das Ergebnis nicht genau ist.

Signalisiert, dass beim Runden Ziffern ungleich null verworfen wurden. Das gerundete Ergebnis wird zurückgegeben. Über Flag oder Trap dieses Signals lässt sich erkennen, wann Ergebnisse ungenau sind.

class decimal.InvalidOperation

Es wurde eine ungültige Operation ausgeführt.

Zeigt an, dass eine Operation verlangt wurde, die keinen Sinn ergibt. Nicht als Trap gesetzt, wird NaN zurückgegeben. Mögliche Ursachen:

Infinity - Infinity
0 * Infinity
Infinity / Infinity
x % 0
Infinity % x
sqrt(-x) and x > 0
0 ** 0
x ** (non-integer)
x ** Infinity
class decimal.Overflow

Numerischer Überlauf.

Zeigt an, dass der Exponent nach dem Runden größer als Context.Emax ist. Nicht als Trap gesetzt, hängt das Ergebnis vom Rundungsmodus ab: Entweder wird nach innen zur größten darstellbaren endlichen Zahl gezogen oder nach außen zu Infinity gerundet. In beiden Fällen werden auch Inexact und Rounded signalisiert.

class decimal.Rounded

Es wurde gerundet, möglicherweise ohne Informationsverlust.

Wird signalisiert, sobald das Runden Ziffern verwirft, selbst wenn diese Ziffern null sind – etwa beim Runden von 5.00 auf 5.0. Nicht als Trap gesetzt, wird das Ergebnis unverändert zurückgegeben. Über dieses Signal lässt sich der Verlust signifikanter Ziffern erkennen.

class decimal.Subnormal

Der Exponent war vor dem Runden kleiner als Emin.

Tritt auf, wenn das Ergebnis einer Operation subnormal ist, der Exponent also zu klein. Nicht als Trap gesetzt, wird das Ergebnis unverändert zurückgegeben.

class decimal.Underflow

Numerischer Unterlauf, dessen Ergebnis zu null gerundet wurde.

Tritt auf, wenn ein subnormales Ergebnis durch Runden zu null wird. Auch Inexact und Subnormal werden signalisiert.

class decimal.FloatOperation

Schaltet strengere Regeln für das Mischen von Floats und Decimals ein.

Ist das Signal nicht als Trap gesetzt (die Voreinstellung), ist das Mischen von Floats und Decimals im Konstruktor Decimal, in create_decimal() und bei allen Vergleichsoperatoren erlaubt. Umwandlung und Vergleiche sind beide genau. Jedes Vorkommen einer gemischten Operation wird stillschweigend vermerkt, indem FloatOperation in den Flags des Kontexts gesetzt wird. Ausdrückliche Umwandlungen mit from_float() oder create_decimal_from_float() setzen das Flag nicht.

Andernfalls – das Signal ist als Trap gesetzt – sind nur Gleichheitsvergleiche und ausdrückliche Umwandlungen still. Alle anderen gemischten Operationen lösen FloatOperation aus.

Die folgende Tabelle fasst die Hierarchie der Signale zusammen:

exceptions.ArithmeticError(exceptions.Exception)
    DecimalException
        Clamped
        DivisionByZero(DecimalException, exceptions.ZeroDivisionError)
        Inexact
            Overflow(Inexact, Rounded)
            Underflow(Inexact, Rounded, Subnormal)
        InvalidOperation
        Rounded
        Subnormal
        FloatOperation(DecimalException, exceptions.TypeError)

Anmerkungen zum Gleitkomma

Rundungsfehler durch höhere Genauigkeit abschwächen

Dezimales Gleitkomma beseitigt den Darstellungsfehler im Dezimalsystem – 0.1 lässt sich damit genau darstellen. Manche Operationen können dennoch Rundungsfehler verursachen, wenn Ziffern ungleich null über die feste Genauigkeit hinausgehen.

Die Wirkung von Rundungsfehlern kann sich verstärken, wenn man Größen addiert oder subtrahiert, die sich fast aufheben. Dabei geht Signifikanz verloren. Knuth gibt zwei lehrreiche Beispiele, in denen gerundete Gleitkommaarithmetik mit zu geringer Genauigkeit das Assoziativ- und das Distributivgesetz der Addition zusammenbrechen lässt:

# Examples from Seminumerical Algorithms, Section 4.2.2.
>>> from decimal import Decimal, getcontext
>>> getcontext().prec = 8

>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.5111111')
>>> u + (v + w)
Decimal('10')

>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.01')
>>> u * (v+w)
Decimal('0.0060000')

Mit dem Modul decimal lassen sich diese Identitäten wiederherstellen, indem man die Genauigkeit so weit erhöht, dass keine Signifikanz verloren geht:

>>> getcontext().prec = 20
>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.51111111')
>>> u + (v + w)
Decimal('9.51111111')
>>>
>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.0060000')
>>> u * (v+w)
Decimal('0.0060000')

Besondere Werte

Das Zahlensystem des Moduls decimal bietet besondere Werte, darunter NaN, sNaN, -Infinity, Infinity und zwei Nullen, +0 und -0.

Unendlichkeiten lassen sich unmittelbar erzeugen: Decimal('Infinity'). Sie können außerdem bei der Division durch null entstehen, wenn das Signal DivisionByZero nicht als Trap gesetzt ist. Ebenso kann Unendlichkeit entstehen, wenn über die Grenzen der größten darstellbaren Zahl hinaus gerundet wird und das Signal Overflow nicht als Trap gesetzt ist.

Die Unendlichkeiten sind vorzeichenbehaftet (affin) und lassen sich in arithmetischen Operationen verwenden, wo sie als sehr große, unbestimmte Zahlen behandelt werden. Addiert man zum Beispiel eine Konstante zur Unendlichkeit, ist das Ergebnis wieder unendlich.

Manche Operationen sind unbestimmt und geben NaN zurück oder lösen eine Ausnahme aus, wenn das Signal InvalidOperation als Trap gesetzt ist. 0/0 gibt zum Beispiel NaN zurück, was „not a number“ bedeutet. Diese Art von NaN ist still und fließt, einmal erzeugt, durch weitere Rechnungen, die stets wieder NaN ergeben. Dieses Verhalten kann bei einer Reihe von Rechnungen nützlich sein, bei denen gelegentlich Eingaben fehlen — die Rechnung läuft weiter und bestimmte Ergebnisse werden als ungültig gekennzeichnet.

Eine Abwandlung ist sNaN, das nach jeder Operation signalisiert statt still zu bleiben. Dieser Rückgabewert ist nützlich, wenn ein ungültiges Ergebnis eine Rechnung unterbrechen soll, um besonders behandelt zu werden.

Das Verhalten von Pythons Vergleichsoperatoren kann überraschen, wenn ein NaN beteiligt ist. Eine Gleichheitsprüfung, bei der einer der Operanden ein stilles oder signalisierendes NaN ist, gibt immer False zurück – auch bei Decimal('NaN')==Decimal('NaN') –, eine Ungleichheitsprüfung immer True. Der Versuch, zwei Decimals mit einem der Operatoren <, <=, > oder >= zu vergleichen, löst das Signal InvalidOperation aus, wenn einer der Operanden ein NaN ist, und gibt False zurück, wenn dieses Signal nicht als Trap gesetzt ist. Beachte, dass die General Decimal Arithmetic Specification das Verhalten unmittelbarer Vergleiche nicht festlegt. Diese Regeln für Vergleiche mit einem NaN stammen aus dem Standard IEEE 854 (siehe Tabelle 3 in Abschnitt 5.7). Um den Standard streng einzuhalten, verwende stattdessen die Methoden compare() und compare_signal().

Die vorzeichenbehafteten Nullen können aus Rechnungen entstehen, die unterlaufen. Sie behalten das Vorzeichen, das sich ergeben hätte, wäre die Rechnung mit größerer Genauigkeit ausgeführt worden. Da ihr Betrag null ist, gelten positive und negative Null als gleich und ihr Vorzeichen ist nur ein Hinweis.

Neben den beiden vorzeichenbehafteten Nullen, die verschieden und doch gleich sind, gibt es verschiedene Darstellungen der Null mit unterschiedlicher Genauigkeit, die im Wert gleichwertig sind. Daran muss man sich etwas gewöhnen. Für ein an normalisierte Gleitkommadarstellungen gewöhntes Auge ist nicht sofort ersichtlich, dass die folgende Rechnung einen Wert gleich null zurückgibt:

>>> 1 / Decimal('Infinity')
Decimal('0E-1000026')

Mit Threads arbeiten

Die Funktion getcontext() greift für jeden Thread auf ein eigenes Context-Objekt zu. Getrennte Thread-Kontexte bedeuten, dass Threads Änderungen vornehmen können – etwa getcontext().prec=10 –, ohne anderen Threads ins Gehege zu kommen.

Ebenso weist die Funktion setcontext() ihr Ziel selbsttätig dem aktuellen Thread zu.

Wurde setcontext() vor getcontext() nicht aufgerufen, erzeugt getcontext() selbsttätig einen neuen Kontext für den aktuellen Thread. Neue Kontextobjekte erhalten ihre voreingestellten Werte aus dem Objekt decimal.DefaultContext.

Das Flag sys.flags.thread_inherit_context beeinflusst den Kontext neuer Threads. Ist das Flag falsch, starten neue Threads mit einem leeren Kontext. Dann erzeugt getcontext() beim Aufruf ein neues Kontextobjekt und verwendet die voreingestellten Werte aus DefaultContext. Ist das Flag wahr, starten neue Threads mit einer Kopie des Kontexts des Aufrufers von threading.Thread.start().

Um die Voreinstellungen so zu steuern, dass jeder Thread in der ganzen Anwendung dieselben Werte verwendet, ändere das Objekt DefaultContext unmittelbar. Das sollte geschehen, bevor Threads gestartet werden, damit es keine Wettlaufsituation zwischen Threads gibt, die getcontext() aufrufen. Zum Beispiel:

# Set applicationwide defaults for all threads about to be launched
DefaultContext.prec = 12
DefaultContext.rounding = ROUND_DOWN
DefaultContext.traps = ExtendedContext.traps.copy()
DefaultContext.traps[InvalidOperation] = 1
setcontext(DefaultContext)

# Afterwards, the threads can be started
t1.start()
t2.start()
t3.start()
 . . .

Rezepte

Hier einige Rezepte, die als Hilfsfunktionen dienen und Wege zeigen, mit der Klasse Decimal zu arbeiten:

def moneyfmt(value, places=2, curr='', sep=',', dp='.',
             pos='', neg='-', trailneg=''):
    """Convert Decimal to a money formatted string.

    places:  required number of places after the decimal point
    curr:    optional currency symbol before the sign (may be blank)
    sep:     optional grouping separator (comma, period, space, or blank)
    dp:      decimal point indicator (comma or period)
             only specify as blank when places is zero
    pos:     optional sign for positive numbers: '+', space or blank
    neg:     optional sign for negative numbers: '-', '(', space or blank
    trailneg:optional trailing minus indicator:  '-', ')', space or blank

    >>> d = Decimal('-1234567.8901')
    >>> moneyfmt(d, curr='$')
    '-$1,234,567.89'
    >>> moneyfmt(d, places=0, sep='.', dp='', neg='', trailneg='-')
    '1.234.568-'
    >>> moneyfmt(d, curr='$', neg='(', trailneg=')')
    '($1,234,567.89)'
    >>> moneyfmt(Decimal(123456789), sep=' ')
    '123 456 789.00'
    >>> moneyfmt(Decimal('-0.02'), neg='<', trailneg='>')
    '<0.02>'

    """
    q = Decimal(10) ** -places      # 2 places --> '0.01'
    sign, digits, exp = value.quantize(q).as_tuple()
    result = []
    digits = list(map(str, digits))
    build, next = result.append, digits.pop
    if sign:
        build(trailneg)
    for i in range(places):
        build(next() if digits else '0')
    if places:
        build(dp)
    if not digits:
        build('0')
    i = 0
    while digits:
        build(next())
        i += 1
        if i == 3 and digits:
            i = 0
            build(sep)
    build(curr)
    build(neg if sign else pos)
    return ''.join(reversed(result))

def pi():
    """Compute Pi to the current precision.

    >>> print(pi())
    3.141592653589793238462643383

    """
    getcontext().prec += 2  # extra digits for intermediate steps
    three = Decimal(3)      # substitute "three=3.0" for regular floats
    lasts, t, s, n, na, d, da = 0, three, 3, 1, 0, 0, 24
    while s != lasts:
        lasts = s
        n, na = n+na, na+8
        d, da = d+da, da+32
        t = (t * n) / d
        s += t
    getcontext().prec -= 2
    return +s               # unary plus applies the new precision

def exp(x):
    """Return e raised to the power of x.  Result type matches input type.

    >>> print(exp(Decimal(1)))
    2.718281828459045235360287471
    >>> print(exp(Decimal(2)))
    7.389056098930650227230427461
    >>> print(exp(2.0))
    7.38905609893
    >>> print(exp(2+0j))
    (7.38905609893+0j)

    """
    getcontext().prec += 2
    i, lasts, s, fact, num = 0, 0, 1, 1, 1
    while s != lasts:
        lasts = s
        i += 1
        fact *= i
        num *= x
        s += num / fact
    getcontext().prec -= 2
    return +s

def cos(x):
    """Return the cosine of x as measured in radians.

    The Taylor series approximation works best for a small value of x.
    For larger values, first compute x = x % (2 * pi).

    >>> print(cos(Decimal('0.5')))
    0.8775825618903727161162815826
    >>> print(cos(0.5))
    0.87758256189
    >>> print(cos(0.5+0j))
    (0.87758256189+0j)

    """
    getcontext().prec += 2
    i, lasts, s, fact, num, sign = 0, 0, 1, 1, 1, 1
    while s != lasts:
        lasts = s
        i += 2
        fact *= i * (i-1)
        num *= x * x
        sign *= -1
        s += num / fact * sign
    getcontext().prec -= 2
    return +s

def sin(x):
    """Return the sine of x as measured in radians.

    The Taylor series approximation works best for a small value of x.
    For larger values, first compute x = x % (2 * pi).

    >>> print(sin(Decimal('0.5')))
    0.4794255386042030002732879352
    >>> print(sin(0.5))
    0.479425538604
    >>> print(sin(0.5+0j))
    (0.479425538604+0j)

    """
    getcontext().prec += 2
    i, lasts, s, fact, num, sign = 1, 0, x, 1, x, 1
    while s != lasts:
        lasts = s
        i += 2
        fact *= i * (i-1)
        num *= x * x
        sign *= -1
        s += num / fact * sign
    getcontext().prec -= 2
    return +s

Häufige Fragen zu Decimal

F: decimal.Decimal('1234.5') zu tippen ist mühsam. Lässt sich die Tipparbeit im interaktiven Interpreter verringern?

A: Manche kürzen den Konstruktor auf einen einzigen Buchstaben ab:

>>> D = decimal.Decimal
>>> D('1.23') + D('3.45')
Decimal('4.68')

F: In einer Festkommaanwendung mit zwei Dezimalstellen haben manche Eingaben viele Stellen und müssen gerundet werden. Andere sollen keine überzähligen Ziffern haben und müssen geprüft werden. Welche Methoden sollte man verwenden?

A: Die Methode quantize() rundet auf eine feste Anzahl von Dezimalstellen. Ist der Trap für Inexact gesetzt, eignet sie sich auch zum Prüfen:

>>> TWOPLACES = Decimal(10) ** -2       # same as Decimal('0.01')
>>> # Round to two places
>>> Decimal('3.214').quantize(TWOPLACES)
Decimal('3.21')
>>> # Validate that a number does not exceed two places
>>> Decimal('3.21').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Decimal('3.21')
>>> Decimal('3.214').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Traceback (most recent call last):
   ...
Inexact: None

F: Wenn ich gültige Eingaben mit zwei Stellen habe – wie halte ich diese Invariante in der ganzen Anwendung aufrecht?

A: Manche Operationen wie Addition, Subtraktion und Multiplikation mit einer ganzen Zahl erhalten das Festkomma selbsttätig. Andere wie Division und Multiplikation mit einer nicht ganzen Zahl ändern die Anzahl der Dezimalstellen. Auf sie muss ein quantize()-Schritt folgen:

>>> a = Decimal('102.72')           # Initial fixed-point values
>>> b = Decimal('3.17')
>>> a + b                           # Addition preserves fixed-point
Decimal('105.89')
>>> a - b
Decimal('99.55')
>>> a * 42                          # So does integer multiplication
Decimal('4314.24')
>>> (a * b).quantize(TWOPLACES)     # Must quantize non-integer multiplication
Decimal('325.62')
>>> (b / a).quantize(TWOPLACES)     # And quantize division
Decimal('0.03')

Beim Entwickeln von Festkommaanwendungen ist es praktisch, Funktionen für den quantize()-Schritt zu definieren:

>>> def mul(x, y, fp=TWOPLACES):
...     return (x * y).quantize(fp)
...
>>> def div(x, y, fp=TWOPLACES):
...     return (x / y).quantize(fp)
>>> mul(a, b)                       # Automatically preserve fixed-point
Decimal('325.62')
>>> div(b, a)
Decimal('0.03')

F: Es gibt viele Wege, denselben Wert auszudrücken. Die Zahlen 200, 200.000, 2E2 und .02E+4 haben alle denselben Wert bei verschiedener Genauigkeit. Lassen sie sich in einen einzigen erkennbaren, kanonischen Wert überführen?

A: Die Methode normalize() bildet alle gleichwertigen Werte auf einen einzigen Vertreter ab:

>>> values = map(Decimal, '200 200.000 2E2 .02E+4'.split())
>>> [v.normalize() for v in values]
[Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2')]

F: Wann wird in einer Rechnung gerundet?

A: Nach der Rechnung. Nach der Philosophie der Decimal-Spezifikation gelten Zahlen als genau und werden unabhängig vom aktuellen Kontext erzeugt. Sie dürfen sogar eine größere Genauigkeit haben als der aktuelle Kontext. Die Rechnungen arbeiten mit diesen genauen Eingaben, und erst danach wird auf das Ergebnis der Rechnung gerundet oder eine andere Kontextoperation angewendet:

>>> getcontext().prec = 5
>>> pi = Decimal('3.1415926535')   # More than 5 digits
>>> pi                             # All digits are retained
Decimal('3.1415926535')
>>> pi + 0                         # Rounded after an addition
Decimal('3.1416')
>>> pi - Decimal('0.00005')        # Subtract unrounded numbers, then round
Decimal('3.1415')
>>> pi + 0 - Decimal('0.00005')    # Intermediate values are rounded
Decimal('3.1416')

F: Manche Decimal-Werte erscheinen immer in Exponentialschreibweise. Gibt es einen Weg zu einer Darstellung ohne Exponent?

A: Bei manchen Werten ist die Exponentialschreibweise der einzige Weg, die Anzahl der signifikanten Stellen im Koeffizienten auszudrücken. 5.0E+3 als 5000 zu schreiben hält den Wert zum Beispiel konstant, kann aber die zweistellige Signifikanz des Originals nicht zeigen.

Ist einer Anwendung die Signifikanz nicht wichtig, lassen sich Exponent und abschließende Nullen leicht entfernen; die Signifikanz geht dabei verloren, der Wert bleibt unverändert:

>>> def remove_exponent(d):
...     return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
>>> remove_exponent(Decimal('5E+3'))
Decimal('5000')

F: Lässt sich ein gewöhnlicher Float in ein Decimal umwandeln?

A: Ja, jede binäre Gleitkommazahl lässt sich genau als Decimal ausdrücken, auch wenn eine genaue Umwandlung mehr Genauigkeit braucht, als die Anschauung vermuten lässt:

>>> Decimal(math.pi)
Decimal('3.141592653589793115997963468544185161590576171875')

F: Wie kann ich in einer komplexen Rechnung sicher sein, dass ich kein falsches Ergebnis durch zu geringe Genauigkeit oder Rundungsanomalien bekommen habe?

A: Mit dem Modul decimal lassen sich Ergebnisse leicht prüfen. Bewährt hat sich, Rechnungen mit größerer Genauigkeit und mit verschiedenen Rundungsmodi erneut laufen zu lassen. Stark abweichende Ergebnisse deuten auf zu geringe Genauigkeit, Probleme mit dem Rundungsmodus, schlecht konditionierte Eingaben oder einen numerisch instabilen Algorithmus hin.

F: Mir ist aufgefallen, dass die Genauigkeit des Kontexts auf die Ergebnisse von Operationen angewendet wird, nicht aber auf die Eingaben. Muss ich etwas beachten, wenn ich Werte verschiedener Genauigkeit mische?

A: Ja. Der Grundsatz lautet: Alle Werte gelten als genau, und ebenso die Arithmetik auf diesen Werten. Nur die Ergebnisse werden gerundet. Der Vorteil bei den Eingaben: „Was du tippst, bekommst du auch.“ Ein Nachteil: Die Ergebnisse können sonderbar aussehen, wenn man vergisst, dass die Eingaben nicht gerundet wurden:

>>> getcontext().prec = 3
>>> Decimal('3.104') + Decimal('2.104')
Decimal('5.21')
>>> Decimal('3.104') + Decimal('0.000') + Decimal('2.104')
Decimal('5.20')

Die Lösung besteht darin, entweder die Genauigkeit zu erhöhen oder das Runden der Eingaben mit dem einstelligen Plus-Operator zu erzwingen:

>>> getcontext().prec = 3
>>> +Decimal('1.23456789')      # unary plus triggers rounding
Decimal('1.23')

Andernfalls lassen sich Eingaben beim Erzeugen mit der Methode Context.create_decimal() runden:

>>> Context(prec=5, rounding=ROUND_DOWN).create_decimal('1.2345678')
Decimal('1.2345')

F: Ist die CPython-Umsetzung bei großen Zahlen schnell?

A: Ja. In den Umsetzungen von CPython und PyPy3 binden die C- und CFFI-Fassungen des Moduls decimal die schnelle Bibliothek libmpdec für korrekt gerundete dezimale Gleitkommaarithmetik beliebiger Genauigkeit ein [1]. libmpdec verwendet die Karatsuba-Multiplikation für mittelgroße Zahlen und die zahlentheoretische Transformation für sehr große Zahlen.

Für genaue Arithmetik beliebiger Genauigkeit muss der Kontext angepasst werden: Emin und Emax sollten immer auf die größten Werte gesetzt sein, clamp immer auf 0 (die Voreinstellung). prec zu setzen erfordert etwas Umsicht.

Am einfachsten lässt sich Bignum-Arithmetik ausprobieren, indem man auch für prec den größten Wert verwendet [2]:

>>> setcontext(Context(prec=MAX_PREC, Emax=MAX_EMAX, Emin=MIN_EMIN))
>>> x = Decimal(2) ** 256
>>> x / 128
Decimal('904625697166532776746648320380374280103671755200316906558262375061821325312')

Für ungenaue Ergebnisse ist MAX_PREC auf 64-Bit-Plattformen viel zu groß und der verfügbare Speicher reicht nicht aus:

>>> Decimal(1) / 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
MemoryError

Auf Systemen mit Überbelegung, etwa Linux, ist es ausgefeilter, prec an den verfügbaren Arbeitsspeicher anzupassen. Nehmen wir an, du hast 8 GB RAM und erwartest 10 gleichzeitige Operanden mit höchstens je 500 MB:

>>> import sys
>>>
>>> # Maximum number of digits for a single operand using 500MB in 8-byte words
>>> # with 19 digits per word (4-byte and 9 digits for the 32-bit build):
>>> maxdigits = 19 * ((500 * 1024**2) // 8)
>>>
>>> # Check that this works:
>>> c = Context(prec=maxdigits, Emax=MAX_EMAX, Emin=MIN_EMIN)
>>> c.traps[Inexact] = True
>>> setcontext(c)
>>>
>>> # Fill the available precision with nines:
>>> x = Decimal(0).logical_invert() * 9
>>> sys.getsizeof(x)
524288112
>>> x + 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  decimal.Inexact: [<class 'decimal.Inexact'>]

Im Allgemeinen – und besonders auf Systemen ohne Überbelegung – empfiehlt es sich, noch engere Grenzen zu schätzen und den Trap für Inexact zu setzen, wenn alle Rechnungen genau sein sollen.