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.1und2.2haben im binären Gleitkomma dagegen keine genaue Darstellung. Endbenutzer erwarten normalerweise nicht, dass1.1 + 2.2als3.3000000000000003erscheint, 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.3genau gleich null. Im binären Gleitkomma lautet das Ergebnis5.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.20gleich2.50ist. 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.2ergibt1.56, während1.30 * 1.201.5600ergibt.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
Die General Decimal Arithmetic Specification von IBM, The General Decimal Arithmetic Specification.
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
floatoder ein anderesDecimal-Objekt sein. Ohne value wirdDecimal('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
digitsteht, 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,INFINITYundiNfINitysind also alle zulässige Schreibweisen für positive Unendlichkeit.Ist value ein
tuple, sollte es drei Bestandteile haben: ein Vorzeichen (0für positiv,1für negativ), eintuplevon Ziffern und einen ganzzahligen Exponenten.Decimal((0, (1, 4, 1, 4), -3))gibt zum BeispielDecimal('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 zuDecimal('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 WertNaNzurü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ürFloatOperationgesetzt 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
floatundint. 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 infloatoderint.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ätx == (x // y) * y + x % yerhalten bleibt:>>> -7 // 4 -2 >>> Decimal(-7) // Decimal(4) Decimal('-1')
Die Operatoren
%und//setzen die Operationenremainderbeziehungsweisedivide-integerum, wie die Spezifikation sie beschreibt.Decimal-Objekte lassen sich in arithmetischen Operationen im Allgemeinen nicht mit Floats oder Instanzen von
fractions.Fractionverbinden: Der Versuch, einDecimalzu einemfloatzu addieren, löst zum Beispiel einenTypeErroraus. Mit Pythons Vergleichsoperatoren lässt sich aber eineDecimal-Instanzxmit einer anderen Zahlyvergleichen. 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 gegebeneDecimal-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 aufDecimal-Instanzen. ZweiDecimal-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, undDecimal('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)entsprichtx.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**xan der gegebenen Zahl zurück. Das Ergebnis ist mit dem RundungsmodusROUND_HALF_EVENkorrekt gerundet.>>> Decimal(1).exp() Decimal('2.718281828459045235360287471') >>> Decimal(321).exp() Decimal('2.561702493119680037517373933E+139')
- classmethod from_float(f, /)¶
Weiterer Konstruktor, der nur Instanzen von
floatoderintannimmt.Beachte:
Decimal.from_float(0.1)ist nicht dasselbe wieDecimal('0.1'). Da 0.1 im binären Gleitkomma nicht genau darstellbar ist, wird der Wert als nächstgelegener darstellbarer Wert gespeichert, nämlich0x1.999999999999ap-4. Dezimal entspricht das0.1000000000000000055511151231257827021181583404541015625.Bemerkung
Seit Python 3.2 lässt sich eine
Decimal-Instanz auch unmittelbar aus einemfloaterzeugen.>>> 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,intoderDecimalannimmt, 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
Truezurück, wenn das Argument kanonisch ist, sonstFalse. Derzeit ist eineDecimal-Instanz immer kanonisch, daher gibt diese Operation immerTruezurück.
- is_finite()¶
Gibt
Truezurück, wenn das Argument eine endliche Zahl ist, undFalse, wenn es eine Unendlichkeit oder ein NaN ist.
- is_infinite()¶
Gibt
Truezurück, wenn das Argument positive oder negative Unendlichkeit ist, sonstFalse.
- is_nan()¶
Gibt
Truezurück, wenn das Argument ein (stilles oder signalisierendes) NaN ist, sonstFalse.
- is_normal(context=None)¶
Gibt
Truezurück, wenn das Argument eine normale endliche Zahl ist. GibtFalsezurück, wenn das Argument null, subnormal, unendlich oder ein NaN ist.
- is_signed()¶
Gibt
Truezurück, wenn das Argument ein negatives Vorzeichen hat, sonstFalse. Beachte, dass sowohl Nullen als auch NaNs Vorzeichen tragen können.
- ln(context=None)¶
Gibt den natürlichen Logarithmus des Operanden zur Basis e zurück. Das Ergebnis ist mit dem Rundungsmodus
ROUND_HALF_EVENkorrekt gerundet.
- log10(context=None)¶
Gibt den Logarithmus des Operanden zur Basis zehn zurück. Das Ergebnis ist mit dem Rundungsmodus
ROUND_HALF_EVENkorrekt gerundet.
- logb(context=None)¶
Gibt bei einer Zahl ungleich null den angepassten Exponenten ihres Operanden als
Decimal-Instanz zurück. Ist der Operand null, wirdDecimal('-Infinity')zurückgegeben und das FlagDivisionByZerogesetzt. Ist der Operand eine Unendlichkeit, wirdDecimal('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 ziffernweiseandder 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 ziffernweiseorder 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 undNaN-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 undNaN-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')undDecimal('0.321000e+2')normalisieren zum Beispiel beide zum gleichwertigen WertDecimal('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
InvalidOperationsignalisiert, 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
roundingden Rundungsmodus, sofern angegeben, sonst das Argumentcontext. 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
Emaxoder kleiner alsEtiny()ist.
- radix()¶
Gibt
Decimal(10)zurück, den Radix – die Basis –, in dem die KlasseDecimalihre 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 % otherwird das Vorzeichen des Restes so gewählt, dass sein Absolutwert möglichst klein ist. Genauer ist der Rückgabewertself - n * other, wobeindie ganze Zahl ist, die dem genauen Wert vonself / otheram 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
NaNsind.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')zuDecimal('1.23E+3').
- to_integral(rounding=None, context=None)¶
Gleichbedeutend mit der Methode
to_integral_value(). Der Nameto_integralbleibt aus Kompatibilität mit älteren Versionen erhalten.
- to_integral_exact(rounding=None, context=None)¶
Rundet auf die nächste ganze Zahl und signalisiert
InexactoderRounded, wie es beim Runden angemessen ist. Den Rundungsmodus bestimmt der Parameterrounding, sofern angegeben, sonst das angegebenecontext. 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
InexactoderRoundedzu 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ächstgelegeneintzurückgegeben, wobei Gleichstände zur geraden Zahl gerundet werden und der Rundungsmodus desDecimal-Kontexts übergangen wird. LöstOverflowErroraus, wenn number eine Unendlichkeit ist, oderValueError, wenn es ein (stilles oder signalisierendes) NaN ist.Ist ndigits ein
int, wird der Rundungsmodus des Kontexts beachtet und einDecimalzurückgegeben, das number auf das nächste Vielfache vonDecimal('1E-ndigits')gerundet darstellt. In diesem Fall entsprichtround(number, ndigits)dem Aufrufself.quantize(Decimal('1E-ndigits')). GibtDecimal('NaN')zurück, wenn number ein stilles NaN ist. LöstInvalidOperationaus, 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
TypeErroraus, wenn kwargs ein Attribut liefert, dasContextnicht unterstützt. LöstTypeErroroderValueErroraus, 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_BITSsein.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ßerInexact,RoundedundSubnormal.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
NaNoderInfinitylieber 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
Contextals Vorlage für neue Kontexte. Ein Feld zu ändern – etwa die Genauigkeit – ändert damit die Voreinstellung für neue Kontexte, die der KonstruktorContexterzeugt.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_EVENsowie eingeschaltete Traps fürOverflow,InvalidOperationundDivisionByZero.
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 ausDefaultContextkopiert. Ist das Feld flags nicht angegeben oderNone, 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
0oder1(die Voreinstellung). Steht der Wert auf1, werden Exponenten mit großemEausgegeben, sonst mit kleineme:Decimal('6.02e+23').
- clamp¶
Entweder
0(die Voreinstellung) oder1. Steht der Wert auf1, ist der Exponenteeiner in diesem Kontext darstellbarenDecimal-Instanz streng auf den BereichEmin - prec + 1 <= e <= Emax - prec + 1begrenzt. Ist clamp0, gilt eine schwächere Bedingung: Der angepasste Exponent derDecimal-Instanz ist höchstensEmax. Ist clamp1, 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
1ermöglicht die Kompatibilität mit den dezimalen Austauschformaten fester Breite, die IEEE 754 festlegt.
Die Klasse
Contextdefiniert 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 beschriebenenDecimal-Methoden – mit Ausnahme vonadjusted()undas_tuple()– eine entsprechendeContext-Methode. Für eineContext-InstanzCund eineDecimal-Instanzxentspricht zum BeispielC.exp(x)dem Aufrufx.exp(context=C). JedeContext-Methode nimmt überall dort, wo eine Decimal-Instanz zulässig ist, auch eine ganze Python-Zahl an, also eine Instanz vonint.- clear_flags()¶
Setzt alle Flags auf
0zurück.
- clear_traps()¶
Setzt alle Traps auf
0zurü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
Decimalwerden 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 + 1zurück, den kleinsten Exponentenwert für subnormale Ergebnisse. Tritt ein Unterlauf auf, wird der Exponent aufEtinygesetzt.
- Etop()¶
Gibt einen Wert gleich
Emax - prec + 1zurü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 KlasseDecimalund 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 ** xzurück.
- fma(x, y, z, /)¶
Gibt x multipliziert mit y, plus z zurück.
- is_canonical(x, /)¶
Gibt
Truezurück, wenn x kanonisch ist, sonstFalse.
- is_finite(x, /)¶
Gibt
Truezurück, wenn x endlich ist, sonstFalse.
- is_infinite(x, /)¶
Gibt
Truezurück, wenn x unendlich ist, sonstFalse.
- is_nan(x, /)¶
Gibt
Truezurück, wenn x ein qNaN oder sNaN ist, sonstFalse.
- is_normal(x, /)¶
Gibt
Truezurück, wenn x eine normale Zahl ist, sonstFalse.
- is_qnan(x, /)¶
Gibt
Truezurück, wenn x ein stilles NaN ist, sonstFalse.
- is_signed(x, /)¶
Gibt
Truezurück, wenn x negativ ist, sonstFalse.
- is_snan(x, /)¶
Gibt
Truezurück, wenn x ein signalisierendes NaN ist, sonstFalse.
- is_subnormal(x, /)¶
Gibt
Truezurück, wenn x subnormal ist, sonstFalse.
- is_zero(x, /)¶
Gibt
Truezurück, wenn x eine Null ist, sonstFalse.
- 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
xhochyzurück, modulomoduloreduziert, sofern angegeben.Mit zwei Argumenten wird
x**yberechnet. Istxnegativ, mussyganzzahlig sein. Das Ergebnis ist ungenau, es sei denn,yist 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)ergibtInvalidOperation. IstInvalidOperationnicht als Trap gesetzt, ergibt esDecimal('NaN').Geändert in Version 3.3: Das C-Modul berechnet
power()über die korrekt gerundeten Funktionenexp()undln(). Das Ergebnis ist wohldefiniert, aber nur „fast immer korrekt gerundet“.Mit drei Argumenten wird
(x**y) % moduloberechnet. Für die Form mit drei Argumenten gelten die folgenden Einschränkungen:alle drei Argumente müssen ganzzahlig sein
ymuss nicht negativ seinmindestens eines von
xundymuss ungleich null seinmodulomuss ungleich null sein und höchstens „precision“ Ziffern haben
Der Wert aus
Context.power(x, y, modulo)gleicht dem Wert, den(x**y) % modulomit unbegrenzter Genauigkeit ergäbe, wird aber effizienter berechnet. Der Exponent des Ergebnisses ist null, unabhängig von den Exponenten vonx,yundmodulo. 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 * nzurück, wobei n die ganze Zahl ist, die dem genauen Wert vonx / yam 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
Truezurü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.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 mitder Option --without-decimal-contextvar konfiguriert, verwendet die C-Fassung einen Kontext je Thread statt je Coroutine und der Wert istFalse. 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
EminundEmaxdes 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
Infinityoder-Infinityzurü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
NaNzurü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.Emaxist. 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 zuInfinitygerundet. In beiden Fällen werden auchInexactundRoundedsignalisiert.
- 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.00auf5.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
InexactundSubnormalwerden 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, increate_decimal()und bei allen Vergleichsoperatoren erlaubt. Umwandlung und Vergleiche sind beide genau. Jedes Vorkommen einer gemischten Operation wird stillschweigend vermerkt, indemFloatOperationin den Flags des Kontexts gesetzt wird. Ausdrückliche Umwandlungen mitfrom_float()odercreate_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
FloatOperationaus.
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.