Seite 1 von 1
Runden von Decimal
Verfasst: Freitag 17. Januar 2014, 19:22
von martinjo
Hallo,
ich versuche über
getcontext().prec = 4 Decimal auf 4 Nachkommastellen zu reduzieren. Bekomme jedoch teilweise sehr verwunderlich Werte. So bekomme ich bei test1 4 Nachkommastellen, bei test2 sind es jedoch zu viele. Was hat dass denn für einen Hintergrund?
Code: Alles auswählen
#!/usr/bin/env python
#-*- coding: utf-8 -*-
from decimal import *
getcontext().prec = 4
test1 = Decimal(3.141592653) / Decimal(9)
print test1
test2 = Decimal(1.55)
print test2
Re: Runden von Decimal
Verfasst: Freitag 17. Januar 2014, 19:37
von BlackJack
@martinjo: Den Hintergrund kann ich Dir nicht nennen, aber in der Dokumentation im
decimal — Quick-start Tutorial steht es relativ weit am Anfang, nach dem zweiten Quelltext/Beispiel-Block: „The significance of a new Decimal is determined solely by the number of digits input. Context precision and rounding only come into play during arithmetic operations.”
Re: Runden von Decimal
Verfasst: Freitag 17. Januar 2014, 19:38
von cofi
Zuerst: Wenn du `Decimal` aus Fliesskommazahlen erstellst, machst du etwas falsch, da du damit die Ungenauigkeiten von Fliesskommazahlen direkt importierst.
Dein konkretes Problem ist, dass du eine wichtige Stelle in der Doku ueberlesen hast:
In Zeile 10 hast du, im Gegensatz zu Zeile 8, aber keine arithmetische Operation.
Zum Schluss noch: Eine Praezision von 4 Nachkommastellen ist kein Runden auf 4 Nachkommastellen. Sondern schlicht ein Rechnen mit geringerer Praezision. Sehr wahrscheinlich - schliesslich benutzt du Decimal wohl wahrscheinlich der Genauigkeit wegen, faehrst du besser, wenn du mit hoher Praezision rechnest und dann manuell auf weniger Stellen rundest.
Re: Runden von Decimal
Verfasst: Freitag 17. Januar 2014, 19:45
von pillmuncher
Das
getcontext().prec definiert nicht die Anzahl der Nachkommastellen einer Zahl, sondern die signifikanten Stellen während einer Berechnung im aktuellen Kontext. Beispiele:
Code: Alles auswählen
>>> Decimal('12.34') + Decimal('5678')
Decimal('5690')
>>> Decimal('12.34') + Decimal('.5678')
Decimal('12.91')
>>> Decimal('1234') + Decimal('.5678')
Decimal('1235')
>>> Decimal('1234') + Decimal('56780')
Decimal('5.801E+4')
>>> (Decimal('1234') + Decimal('56780')) / 10
Decimal('5801')
Re: Runden von Decimal
Verfasst: Freitag 17. Januar 2014, 20:36
von BlackJack
@cofi: Vier Nachkommastellen kann durchaus gewünscht sein, zum Beispiel bei Finanzrechnungen. Da würde man `Decimal` nämlich nicht wegen einer hohen Genauigkeit verwenden, sondern gerade weil man so etwas sagen kann wie „die Rechnungen müssen mit vier signifikanten Nachkommastellen durchgeführt werden” und weil man die Kontrolle über verschiedene Arten zu runden hat. IIRC hatte martinjo hier auch schon Fragen in der Richtung wie man Finanzinformationen (Kurse, …) aus Webseiten scraped, es ist also nicht unwahrscheinlich das er tatsächlich ”wenig” Präzision und mehr Kontrolle darüber als bei `float` haben möchte.

Re: Runden von Decimal
Verfasst: Freitag 17. Januar 2014, 20:50
von pillmuncher
@BlackJack: Dass es um Geld geht hatte ich mir auch gedacht (denn geht es nicht immer um Geld...?).
@ martinjo: Decimal ist nicht nur wegen der fehlenden fixen Nachkommastellen wenig geeignet um Geldbeträge zu repräsentieren. Es gibt noch mehr Gründe:
Code: Alles auswählen
>>> from decimal import Decimal, getcontext
>>> getcontext().prec = 2
>>> my_dollars = Decimal('1000.00')
>>> my_euros = Decimal('2000.00')
>>> my_money = my_dollars + my_euros
>>> float(my_money)
3000.0
>>> i_wanna_get_rich = my_euros ** 2 # Quadrat-€
>>> float(i_wanna_get_rich)
4000000.0
Ein Web-Suche nach
python "money class" sollte dir etwas passenderes als Decimal liefern.
Re: Runden von Decimal
Verfasst: Samstag 18. Januar 2014, 17:18
von martinjo
Hallo
@all Danke für die vielen Antworten.
@BlackJack/pillmuncher: Ja, dass mit "getcontext().prec = 4" hatte ich falsch verstanden bzw. falsch beigebracht bekommen. Das jetzt richtig zu verstehen hilft mir schon mal viel weiter.
@cofi Das ist ein zweiter, wichtiger Punkt, Vielen Dank.