Ich habe eine Frage zum Modul decimal.py von Python

...komplette Frage anzeigen

2 Antworten

Hi!

Ich kann dir das nicht bis ins letzte beantworten, aber immerhin soviel:

Mathematische Ungenauigkeiten, die du erlebst, sind kein spezielles Python-Problem. Sie lassen sich auch nicht "einfach" abstellen indem man selbst irgendwelche Module entwerfen würde. Und das Problem tritt auch bei allen anderen Sprachen auf.

 

Das Problem ist ganz einfach dass man im dezimalen Zahlensystem rechnet - ein Computer aber unterm Strich nur das binäre Zahlensystem beherrscht. Und nicht jede Dezimalzahl lässt sich problemlos als Binärzahl darstellen.

Daher gibts für die Datentypen "float", also Fließkommazahlen, für die Auslegung "single" (32bit) und "double" (64bit) jeweils definierte Aussagen zur Genauigkeit:

docs.python.org/2/tutorial/floatingpoint.html

Mir ist unerklärlich wie QBASIC beim rechnen irgendetwas anderes oder besseres bewerkstelligen soll, da QBASIC - wie alle mir bekannten Sprachen - auch nur mit diesen Datentypen hantiert, was besseres oder präziseres als "double float" hat die Sprache auch nicht anzubieten.

 

Mangels Notwendigkeit hab ich das genannte Modul "decimal" nicht selbst benutzt (...ich bin bisher ganz gut mit den üblichen Nachkommastellen zurechtgekommen), ich denke allerdings nicht dass das Modul unausgereift ist. Klar kann man Bugs nie ganz ausschließen, aber das Modul ist fester Python-Bestandteil -- das sollte schon seinen Zweck erfüllen.

Korrekt ist dass man unter Verwendung eines solchen Moduls auch die Syntax entsprechend anwenden muss - das Modul stellt nunmal den neuen Datentypen "decimal" zur Verfügung, das muss man im Code dann auch entsprechend deklarieren.

Dein "Problem" was die ausgegebene "Genauigkeit" betrifft lässt sich in mehrere Dinge unterteilen:

Einmal ist es wichtig zu verstehen wann die angegebene "precision" wirkt und was sie tut. Du hast trotz angegebener precision von 2 eine Zahl mit sechs Nachkommastellen definiert. Beides wiederspricht sich nicht - kann man problemlos beides machen. Sobald du die definierte, sechsstellige Zahl aber zum rechnen mit decimal benutzt greift die angegebene Genauigkeit.

docs.python.org/2/library/decimal.html

Und dann sollte man berücksichtigen dass man drei Dinge tun kann: Man kann die Präzision einer Berechnung direkt auf zwei Nachkommastellen begrenzen. Man kann die Berechnung auch mit der üblichen Genauigkeit vornehmen und das Ergebnis auf zwei Nachkommastellen runden. Und man kann die berechnete Zahl unverändert lassen und lediglich die Ausgabe auf zwei Nachkommastellen beschränken, durch Formatierungen.

Das sind drei verschiedene Dinge die eine Zahl beeinflussen können - aber es sind drei verschiedene Wege die je nach Situation auch zu unterschiedlichen Ergebnissen führen können.

Man sollte sich also überlegen wo man welche Möglichkeit verwendet. Um eine Zahl z. B. auf zwei Nachkommastellen anzuzeigen würd ich sicher nicht decimal verwenden, sondern entweder runden oder formatieren.

...ausserdem frag ich mich gerade warum man überhaupt mit decimal eine Möglichkeit für präzisere Berechnungen nutzt wenn man die Ergebnisse dann sowieso nur auf zwei Nachkommastellen braucht :-)

 

Ich weiß nicht inwiefern das in Frage kommt, aber ich denk es schadet nicht erstmal die Standard-Rechenfunktionen und dann evtl. das math-Modul zu begutachten, bevor man sich dann mit decimal rumschlägt. Wär ja eventuell ne Hilfe.

Grüße!

Erst einmal recht herzlichen Dank für deine Antwort sphxx !

Das zweite Beispiel mit der Rundung auf 2 Stellen habe ich nur erwähnt, weil es selbst da zu Merkwürdigkeiten kam. Das hat mit dem ersten Beispiel nichts zu tun, selbstverständlich möchte ich eine hohe Genauigkeit haben.

Ich habe mal e ^ 2 ausrechnen lassen und bin zu folgenden Ergebnissen gekommen ->

  • Windows Taschenrechner CALC.EXE, Absoluter Fehler 4 * 10 ^ -32

  • QBASIC, absoluter Fehler 1 * 10 ^ -16

  • Python, absoluter Fehler 5 * 10 ^ -16

Obwohl hier QBASIC für seine Verhältnisse auch recht schlecht abschneidet, ist der absolute Fehler von Python trotzdem noch 5 Mal höher !

Das Problem bei sehr umfangreichen Rechnungen ist, das sich kleine Rechenungenauigkeit im Laufe der Zeit aufsummieren !!!

Vielleicht übertreibe ich ja auch nur, aber mich hat das überrascht, weil ich es vom hochgelobten Python nicht erwartet habe.

Der Hinweis mit dem math-Modul ist prima, werde ich mir mal anschauen !

0
@Spielkamerad

Hi again!

...also - ich bin echt schlecht in Mathe. Ich bin da sicher nicht die geeignete Person um da irgendetwas zu erklären. Aber ich versuchs mal...

(Ich wurde auf das Problem schonmal aufmerksam, hab dann aber festgestellt dass das echt kompliziert ist - und es wieder ignoriert. Und jetzt kommst du und stößt mich da wieder direkt drauf. Muss ich vielleicht doch nochmal lernen, das alles :-)  )

 

Fest steht jedenfalls dass Computer nicht in der Lage sind jede beliebige Zahl darzustellen.

Selbst die simple Zahl 0.1 lässt sich für nen PC nicht exakt Abbilden. Die geläufigen Sprachen arbeiten daher eben mit den bekannten Fließkomma-Datentypen - die sind nur bedingt genau und sind eher eine "binäre Interpretation" der ursprünglichen Zahl.

Daher auch:

Warning: Do not depend on the exactness of floating point arithmetic, even for apparently simple expressions!

(anh.cs.luc.edu/python/hands-on/3.1/handsonHtml/float.html)

 

Für die meisten Anwendungsfälle - herkömmliche Berechnungen eben - ist das mehr als ausreichend, jemand hat mal gemeint dass diese Genauigkeit schließlich auch genügt um Sonden über doch relativ große Distanzen ins All zu schießen ;-)

Generell ist es aber für alle Sprachen ein Problem mit exakter Genauigkeit im Dezimalsystem zu rechnen.

Ich hab keine Ahnung welche Referenz-Rechnung du mit e^2 aufstellen willst, ich bin wie erwähnt schlecht in Mathe - aber mit dem Randwissen dass Computer in diesen Bereichen eben diverse Probleme haben könnte man auch das Taschenrechner-Ergebnis anzweifeln. Oder das von QBASIC.

Die Systeme müssen sich eben alle irgendetwas einfallen lassen um mehr Präzision darstellen und anwenden zu können. Irgendwie macht das auch ein Taschenrechner. Irgendwie macht das QBASIC. Es macht jedenfalls den Anschein als gäbs da auch nicht "die eine allgemeingültige" Lösung:

de.wikipedia.org/wiki/Flie%C3%9Fkommazahl#IEEE_754_und_andere_Normen

Wundern würds mich jedenfalls nicht wenn auch diese unterschiedlichen Ergebnisse nur endlich präzise sind und die verwendeten Rechenwege eben doch "nur" Näherungen sind.

 

Bei Python hilft dir das genannte "math"-Modul nicht wenns um die Genauigkeit geht. Der Tip war Quatsch, sorry. Gut, du willst Dinge berechnen, da ist math vielleicht generell mal nen Blick wert.

Ich hab mittlerweile mal nen kurzen Blick auf decimal geworfen - und das sollte ziemlich genau das sein was du suchst.

Funktioniert bei meinen paar Tests auch ganz wunderbar.

Ich hab hier mal en paar simple Python-Zahlendinge ausprobiert, eventuell bietet dir das nochmal ne kleine Übersicht über unterschiedliche Verhaltensweisen.

Besonders die letzten beiden Zeilen dürften dich dann im Bezug auf decimal und eine höhere Genauigkeit interessieren - naja, du kannst ja mal nen Blick drauf werfen:

http://pastebin.com/Zu35Jt39

 

...und falls du das mal wirklich etwas genauer wissen willst bin ich noch darüber gestolpert:

docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

Ich weiß nicht ob ich mir das mal durchles, aber es macht den Anschein als würde das Problem da einmal vollumfassend behandelt werden.

 

Mit etwas Glück reicht es für deine Vorhaben also wenn du decimal richtig anwendest, generell glaub ich nicht dass man Python da vorschnell irgendwie verurteilen sollte. Ich bin da kein Profi, aber meine Erfahrung ist dass die Sprache einfach alles irgendwie brauchbar hinbekommt. Ich hab da Hoffnung :-)

Ich hab auch noch weitere Mathe-Module gefunden, Drittanbieter-Zeugs, die eben auch besonderes Augenmerk auf Präzision legen... müsste dann aber eben in Python integriert werden - und naja, wofür gibts denn das Standard-Modul. Ich würd mich erstmal damit befassen.

Grüße!

1
@sphxx

Hallo sphxx !

Dein Tipp war gut, ich habe jetzt herausgefunden, das das Python - Package genannt mpmath es tatsächlich erlaubt, die 5 grundlegenden Operationen Addition, Subtraktion, Multiplikation, Division und Potenzieren mit praktisch unbegrenzter Genauigkeit durchzuführen (habe ich mit der Eulerschen Zahl überprüft), und das sogar noch sehr schnell ! Ausserdem bietet mpmath noch extrem viele weitere Highlights !

Allerdings war es gar nicht leicht, mpmath in Python zu installieren, aber ich habe folgendes Zitat gefunden -->

The mpmath setup files can be downloaded from the mpmath download page or the Python Package Index. Download the source package (available as both .zip and .tar.gz), extract it, open the extracted directory, and run python setup.py install

Man muss das mpmath - Package downloaden, dann extrahieren, dann die Datei python.exe kopieren (vervielfältigen) und in den Extraktionsordner packen, dann muss man die Kommandozeile cmd (Windows - Taste + R dann cmd eingeben) aufrufen, in den Extraktionsordner gehen und python setup.py install eintippen.

http://mpmath.googlecode.com/svn/trunk/doc/build/index.html

Eine Dokumentation zu mpmath findet man hier -->

sage.math.washington.edu/home/fredrik/mpmath/doc/0.18/index.html

Ich hab keine Ahnung welche Referenz-Rechnung du mit e^2 aufstellen willst, ich bin wie erwähnt schlecht in Mathe - aber mit dem Randwissen dass Computer in diesen Bereichen eben diverse Probleme haben könnte man auch das Taschenrechner-Ergebnis anzweifeln. Oder das von QBASIC.

Das fantastische an der Eulerschen Zahl e , das inzwischen mindestens eine Millionen Nachkommastellen absolut sicher bekannt sind ! Deshalb eignet sie sich so gut um nachzuprüfen, wie genau ein Computer oder Taschenrechner rechnet. Und deshalb konnte ich auch auf meine Zahlenergebnisse von oben kommen.

datendieter.de/item/EulerscheZahlauf1Millionen_Nachkommastellen

1
@Spielkamerad

...hach, Python. Hat einfach für jeden Anwendungsfall ne Lösung parat :-)

Dieses Modul war mir bis eben gänzlich unbekannt! Gut zu wissen - falls mans mal braucht. Danke für die Info(s)!

Hm, der Installationsvorgang von Drittanbieter-Modulen kann manchmal etwas hakelig sein, ja... aber solangs funktioniert ;-)

Kannst du mir verraten ob ein formatierter decimal-Wert wie etwa:

print format(Decimal('0.1'), '.30f')

...für dich auch funktionieren würde? Ich bin nur neugierig ob dein Vorhaben auch mit Python-Bordmitteln funktionieren würde :-)

Klar wärs dann nicht sooo besonders schön andauernd derartige Formatierungen vorzunehmen, wenn das mpmath-Modul das ganze einfacher gestaltet würd ich das auch bevorzugen :-)

Grüße!

1
@sphxx

Ich bin erst vor kurzem mit Python angefangen und kann dir leider deine Frage nicht beantworten.

Diesen Befehl kenne ich bislang noch nicht, aber egal was ich eingebe, auch ohne Decimal zu verwenden bekomme ich immer die Mitteilung "invalid Syntax", egal, ob ich eine Zahl oder eine Variable eingebe. Vielleicht habe ich es auch einfach nur falsch geschrieben.

Den Befehl "print format" habe ich bislang bei Google noch nicht gefunden...

0
@Spielkamerad

Achso, ja - na, das ist normal und das wird mit der Zeit besser :-)

Hauptsache ist du kommst ans Ziel. Und danke fürs Sternchen!

0

Leider hat der Texteditor von Gutefrage.net meine Formatierung geändert, ich hoffe man kann es trotzdem erkennen, meine Eingaben haben so ausgesehen -->

import decimal

Zahl=0.387951

decimal.Decimal(Zahl)

decimal.getcontext().prec=16

Zahl=0.387951

decimal.Decimal(Zahl)

decimal.getcontext().prec=16

decimal.Decimal(Zahl) + decimal.Decimal('0')

decimal.getcontext().prec=2

decimal.Dezimal('0.123456')

decimal.Dezimal('0.123456') + decimal.Dezimal('0')

Was möchtest Du wissen?