Seite 1 von 1

ganz genaue Zahlen

Verfasst: Dienstag 13. Oktober 2009, 14:18
von bughunter
Hallo liebe Forumsleser,

ich muss mit Python eine "list" mit "float" Elementen in eine Datei schreiben, allerdings habe ich das Problem ich muss am besten die Zahlen unverändert rausschreiben können. Nun bin ich über die Standardformatierung der str()-Funktion auf die Nase gefallen und habe mittels

Code: Alles auswählen

str("%16.16lf"%zahl)
das ganze etwas genauer hinbekommen. Nun bereiten mir Werte Kopfschmerzen die wohl noch genauer sein müssen. Ich hatte vorher schöne exponentiale Zahlen wie 1.23423e-022 usw. die fallen dann natürlich unter den Tisch und Werte wie -0.00000000 lassen erahnen das was fehlt.

Hat jemand eine Idee wie ich die Zahlen möglichst genau in einen String wandeln kann???
(die float liste kommt eigenlich aus C raus aber ich kann dort nichts verändern, ich muss mich mit der liste und den float Werten rumschlagen :wink: )

Meine Idee war "%g" (Edit: hoppla ich meinte %e) und alles wird gut, nur weiß ich nicht ob dies nun richtig ist und den float (hat ja double precision) korrekt umwandelt. "%x" sah komisch aus, müsste Hexadezimal nicht am besten sein.

Das Problem bereitet mir echt Kopfzerbrechen.

Vielen Dank im Voraus für Eure Ideen.

Viele Grüße
bughunter

P.S.: ich bin auf Python 2.4.1 angewiesen :!:

Re: ganz genaue Zahlen

Verfasst: Dienstag 13. Oktober 2009, 14:23
von numerix
So richtig verstanden habe ich jetzt nicht, wo GENAU dein Problem ist.
Vielleicht ist es das, was du suchst: http://docs.python.org/3.1/library/decimal.html


Edit: Jetzt hab ich verstanden, worum es geht. Der Link oben hilft nicht.
Ich glaube, das ist es, was du willst:

Code: Alles auswählen

>>> a = 3.0/7**20
>>> a
3.7597628682590546e-17
>>> print "%.50e" %a
3.75976286825905464077223469810399383600908046476619e-17

Verfasst: Dienstag 13. Oktober 2009, 14:33
von bughunter
Hallo numerix,

ich bekomme eine Liste die etwa so aussieht:

liste(

float 1
float 2
float 3

float 4
float 5
float 6

float 7
float 8
float 9
)

diese float-Werte möchte ich gleich in einen string umwandeln und als Zeichenkette weiterverwenden. Die Werte landen später in einer Textdatei. Decimal ist gut gemeint, ich dachte nur ich brauche die garnicht, aber falls sich hier eine Lösungsmöglichkeit bietet bin ich ganz Ohr.

Viele Grüße
bughunter

Verfasst: Dienstag 13. Oktober 2009, 14:37
von bughunter
Hallo numerix,

fast wie ein chat hier :wink: Danke!
Ich weiß nicht, wie genau der float im Python ist, double liege bei 15-16 Stellen Genauigkeit (sei 64 bit breit), laufe ich hier Gefahr durch die Formatierung Datenmüll anzufügen?!

Etwa sowas bekomme ich mit "%16.16lf" heraus, ist aber wie gesagt ungünstig:

Code: Alles auswählen

 0.9977260491478370 0.0334070537177052 0.0585380185329267
-0.0257925263667679 0.9916544868481860 -0.1263175534020790
-0.0622693860213720 0.1245204701074090 0.9902611655966129 
1008.8248444808501000 -729.8262172489220300 428.0336341556750300
Schon interessant was bei mir mit Python 2.5.2 herauskommt:

Code: Alles auswählen

Python 2.5.2 (r252:60911, Feb 21 2008, 13:11:45) [MSC v.1310 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.

    ****************************************************************
    Personal firewall software may warn about the connection IDLE
    makes to its subprocess using this computers internal loopback
    interface.  This connection is not visible on any external
    interface and no data is sent to or received from the Internet.
    ****************************************************************
    
IDLE 1.2.2      
>>> a=3.0/7**20
>>> a
3.7597628682590546e-017
>>> str(a)
'3.75976286826e-017'
>>> str("%.50e"%a)
'3.75976286825905460000000000000000000000000000000000e-017'
>>> print "%.50e"%a
3.75976286825905460000000000000000000000000000000000e-017
>>> 

Viele Grüße
bughunter

Verfasst: Dienstag 13. Oktober 2009, 15:01
von EyDu
Hallo.

Was erwartest du denn? Alle ausgegebenen Zahlen sind doch auf mindestens 15 Stellen angegeben. Wie du ja selber schon festgestellt hast, werden auch nicht mehr garantiert. Allle verbleibenden Stellen können dann einfach mit Nullen aufgefüllt werden. Vielleicht erzählst du einfach mal, was du bei Zahlen wie 1008.8248444808501000 oder 0.9916544868481860 erwartest.

Verfasst: Dienstag 13. Oktober 2009, 15:05
von Defnull
Vielleicht liegts an Windows. Meine Linux-Versionen (getestet mit 2.5.4 und 2.6.2) geben folgendes aus:

Code: Alles auswählen

>>> print "%.50e" % (3.0/7**20)
3.75976286825905464077223469810399383600908046476619e-17

Verfasst: Dienstag 13. Oktober 2009, 15:15
von EyDu
Ja, aber dann sollte man es mit der Genauigkeit nicht mehr so ernst nehmen:

Code: Alles auswählen

>>> print "%.50e" % (1.0/3.0)
3.33333333333333314829616256247390992939472198486328e-01

Verfasst: Dienstag 13. Oktober 2009, 15:19
von numerix
Defnull hat geschrieben:Vielleicht liegts an Windows.
Es scheint auch etwas mit der (C)Python-Implementation zu tun zu haben.
Bei mir liefern alle (auf meinem Rechner vorhandenen) CPython-Versionen (2.5, 2.6, 3.0, 3.1) die Darstellung

Code: Alles auswählen

>>> print("%.50e" %(3.0/7**20))
3.75976286825905464077223469810399383600908046476619e-17
Jython hingegen (2.2 und 2.5) liefert

Code: Alles auswählen

>>> print("%.50e" %(3.0/7**20))
3.75976286825905500000000000000000000000000000000000e-17
Exakt wäre im übrigen

Code: Alles auswählen

>>> from decimal import Decimal, getcontext
>>> getcontext().prec = 50
>>> print Decimal(3)/Decimal(7**20)
3.7597628682590546995108942577230359476147421084074E-17

Verfasst: Dienstag 13. Oktober 2009, 15:23
von bughunter
Ich benötige möglichst genaue Werte, da ich Transformationsmatrizen verarbeite. Ist eine Zahl ungenau wirkt sich das auf die Lage eines Volumenkörpers im Raum aus. Was mich wunderte, ist, dass ich teilweise e-Zahlen hatte die im Exponent hohe Genauigkeiten stehen haben - so hier:

Code: Alles auswählen

#per str(floatzahl) erzeugt:
-5.29395592034e-023 -3.44611707218e-024 1.0 -1.77809157735e-016 7.94093388051e-023 
Edit: auf Linux sind es auch mehr Stellen :lol: nur muss ich WinDAUs benutzen

Viele Grüße
bughunter

Verfasst: Dienstag 13. Oktober 2009, 15:28
von EyDu
Das liegt an der internen Darstellung der Zahlen. Die Genauigkeit gilt für die Mantisse, der Exponent wird separat gespeichert. Vielleicht solltest du dir dazu den Wikipedia-Artikel durchlesen.
bughunter hat geschrieben:Edit: auf Linux sind es auch mehr Stellen Laughing nur muss ich WinDAUs benutzen
Diese haben allerdings keine Aussagekraft.

Verfasst: Dienstag 13. Oktober 2009, 15:37
von numerix
EyDu hat geschrieben:Diese haben allerdings keine Aussagekraft.
Genau.
@bughunter: Sieh dir mein Beispiel oben doch nochmal an.

Die Frage wäre auch, wie genau die float-Werte sind, die du bekommst.
Wenn du die Berechnung in Python durchführen könntest (und es auf die Rechengeschwindigkeit nicht ankommt), dann wäre das Decimal-Modul doch das richtige. Da kannst du eine beliebige (tatsächliche!) Genauigkeit festlegen.

Verfasst: Dienstag 13. Oktober 2009, 15:45
von bughunter
@numerix:

Ich frage die Werte über eine C/C++ Erweiterung im Python ab, es müssen wohl double Werte im C sein die etwa mittels:

Code: Alles auswählen

PyObject* PyFloat_FromDouble(double v)
in eine "list" geschossen werden. So kann ich nur die floats nehmen und will diese möglichst unverändert rausschreiben.

:twisted: und wenn auch BINÄR :wink: Zahlen wären aber hübscher

Nochmals Dank für Eure regen Beiträge!

Viele Grüße
bughunter

Verfasst: Dienstag 13. Oktober 2009, 17:01
von Defnull
Warum verwendest du überhaupt eine verlustbehaftete Zahlenrepresentation, wenn die so genau sein müssen?

Verfasst: Dienstag 13. Oktober 2009, 23:53
von veers
Python floats sind doubles. Aber wenn die Präzision derart wichtig ist sind wie schon gesagt auch doubles nichts für dich.

Verfasst: Mittwoch 14. Oktober 2009, 09:06
von bughunter
Genau, das sind im Prinzip doubles, heißen nur float (mit double precision).
Wie gesagt ich kann nur das nehmen was ich bekomme, ich weiß das es im C auch nicht genauer zugeht, allerdings birgt eine Typenkonvertierung immer die Gefahr des Datenverlusts und das wollte ich ausschließen.

Numerix und EyDu haben mir gute hinweise gegeben, die "%.50e" ist eine gute Lösung. Das Mantisse und Exponent getrennt sind erklärt dann auch meine ergebnisse mit "%16.16lf". Ist eine sehr genaue Zahl z.B.: 1.23432e-024 dabei, dann habe ich Datenverlust.

Ich werde vorsichtshalber wohl erstmal mit str() nachsehen ob es eine e-Zahl ist so spare ich mir die Größenprüfung und im Falle keiner e-Zahl
benutze ich "%16.16lf" das sollte genau genug sein, oder was haltet Ihr davon?

@defnull: Ich hätte auch lieber Strings bekommen :wink: anstatt Zahlen anfassen zu müssen die ich ohnehin als Text rausschreibe.

Viele Grüße
bughunter

Verfasst: Mittwoch 14. Oktober 2009, 09:36
von numerix
Es gibt noch einen anderen Weg:
Das math-Modul bietet die Möglichkeit, Mantisse und Exponent eines float Wertes zu ermitteln und auch umgekehrt aus beiden wieder den float zusammenzusetzen. Damit könnte es gelingen, die erhaltenen float (= double) Werte ohne Verlust zu speichern und auch wieder einzulesen (man sollte noch ein paar mehr Beispiele testen, um sicher zu gehen).

Code: Alles auswählen

>>> from math import frexp, ldexp
>>> a = 3.0/7**20
>>> a
3.7597628682590546e-17
>>> m,e = frexp(a)
>>> m
0.67729866609971623
>>> e
-54
>>> s = "%.17f" %m
>>> s
'0.67729866609971623'
>>> n = float(s)
>>> n
0.67729866609971623
>>> b = ldexp(n,e)
>>> a==b
True

Verfasst: Mittwoch 14. Oktober 2009, 10:19
von bughunter
:idea: AH :idea: , das ist noch eine interessante Option, Danke!
Aber warum eigentlich "%.17f" und nicht "%.16" woher weiß man das?
Im Interaktiven Modus kümmert sich glaub ich "repr()" darum das Objekt anzuzeigen, ich müsste quasi die Stellenanzahl noch ermitteln oder?


Viele Grüße
bughunter

Verfasst: Mittwoch 14. Oktober 2009, 11:02
von gkuhl
Das hängt damit zu zusammen, das 54 Nachkommastellen im Binärsystem etwa 17 Nachkommastellen im Dezimalsystem entsprechen. Zum Verständnis kannst du dir die Norm IEEE 754 anschauen.

Grüße
Gerrit