Rechnen mit "float(str(Zahl)" ?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Leto
User
Beiträge: 6
Registriert: Donnerstag 27. Juli 2006, 15:23

Hallo,
ich habe eine seltsame "Entdeckung" gemacht, die erfahrenen Programmieren in Python wahrscheinlich bekannt sein dürfte.

Da ich mich gerade mit der Ungenauigkeit von Python float's herumschlagen muss - Stichwort:

Code: Alles auswählen

>>>0.3-0.1 == 0.2 
False
- bin ich ganz zufällig auf folgende Lösung dieses Problems gestoßen:

Code: Alles auswählen

>>>float(str(0.3-0.1))==0.2
True
Wie kommt das? Warum geht das eine, das andere aber nicht. Rechenfehler bleibt doch Rechenfehler.
pyStyler
User
Beiträge: 311
Registriert: Montag 12. Juni 2006, 14:24

Hi,

also bei mir sieht die Rechnung so aus

Code: Alles auswählen

>>> float (0.3-0.1) == 0.19999999999999998
True

#float 0.2 ist in python

>>> float(0.2)
0.20000000000000001
vlt hilft dir das ein bisschen.
helmut
User
Beiträge: 57
Registriert: Mittwoch 2. November 2005, 07:45
Wohnort: Dormagen

Gestrichen, da hatte ich Addition und Subtraktion vertauscht.

Gruss, Helmut
Leto
User
Beiträge: 6
Registriert: Donnerstag 27. Juli 2006, 15:23

Also mir ist schon klar, dass (0.3-0.1) und 0.2 in Python nicht gleich sind.
ich verstehe nur nicht, warum str(0.3-0.1) auf einmal '0.2' ist.
Wird da gerundet? Und wenn ja, an welcher Stelle bzw. nach welchem System?
Benutzeravatar
DatenMetzgerX
User
Beiträge: 398
Registriert: Freitag 28. April 2006, 06:28
Wohnort: Zürich Seebach (CH)

Code: Alles auswählen

>>> round(0.3-0.1, 1)
0.20000000000000001
>>> round(0.3-0.1, 1) == 0.2
True

So geht es ;)
pyStyler
User
Beiträge: 311
Registriert: Montag 12. Juni 2006, 14:24

Leto hat geschrieben:Also mir ist schon klar, dass (0.3-0.1) und 0.2 in Python nicht gleich sind.
ich verstehe nur nicht, warum str(0.3-0.1) auf einmal '0.2' ist.
Wird da gerundet? Und wenn ja, an welcher Stelle bzw. nach welchem System?
vielleicht ist es so besser .

Code: Alles auswählen

>>> a=str(0.3-0.1)
>>> b=0.2
>>> a == b
False
>>> print float(a)
0.2
>>> float(a) == b
True
weisst du jetzt was da passiert ist ?
Im übrigen es wird nirgends wo gerundet ( nur mal als hilfe )!Den Rest musst du selber rausfinden :D
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Um hier mal Klarheit zu schaffen:
Floats sind nicht nur in Python ungenau. Sie sind überall ungenau, weil das nicht anders geht, wenn man dezimale Zahlen in einem Binärsystem mit einer begrenzten Anzahl von Stellen repräsentiert. (Deswegen gibts ja auch das decimal-Modul).

Bei Anwendung von str() auf einen float wird auf 12 Stellen, bei repr() auf 17 Stellen "gerundet". Eventuelle Nullen am Ende werden dann entfernt. Das führt dazu, dass die Ausgabe von

>>> 0.3-0.1
0.1999...

anders aussieht als von

>>> print 0.3-0.1
0.2

da print str() verwendet, das Prompt an sich aber repr().
pyStyler
User
Beiträge: 311
Registriert: Montag 12. Juni 2006, 14:24

Hi birkenfeld
birkenfeld hat geschrieben: Bei Anwendung von str() auf einen float wird auf 12 Stellen, bei repr() auf 17 Stellen "gerundet". Eventuelle Nullen am Ende werden dann entfernt. Das führt dazu, dass die Ausgabe von
weiss nicht so genau was du damit meinst !

Code: Alles auswählen

>>> x=float(0.2)
>>> y=str(0.2)
>>> x
0.20000000000000001
>>> y
'0.2'
>>> float(y)
0.20000000000000001
>>> 
Benutzeravatar
DatenMetzgerX
User
Beiträge: 398
Registriert: Freitag 28. April 2006, 06:28
Wohnort: Zürich Seebach (CH)

Code: Alles auswählen

>>> str(0.3)
'0.3'
>>> repr(0.3)
'0.29999999999999999'
str() entfernt die überflüssigen 0s und rundet zuerst noch
pyStyler
User
Beiträge: 311
Registriert: Montag 12. Juni 2006, 14:24

DatenMetzgerX hat geschrieben:

Code: Alles auswählen

>>> str(0.3)
'0.3'
>>> repr(0.3)
'0.29999999999999999'
str() entfernt die überflüssigen 0s und rundet zuerst noch
sorry aber das ist so nicht ganz richtig.

Code: Alles auswählen

>>> x=str(0.3)
>>> type(x)
<type 'str'>
>>> y=float(x)
>>> type(y)
<type 'float'>
>>> 
>>> x
'0.3'
>>> y
0.29999999999999999
>>> 
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

pyStyler hat geschrieben:
DatenMetzgerX hat geschrieben:

Code: Alles auswählen

>>> str(0.3)
'0.3'
>>> repr(0.3)
'0.29999999999999999'
str() entfernt die überflüssigen 0s und rundet zuerst noch
sorry aber das ist so nicht ganz richtig.
Doch, man kann es so sagen.
pyStyler hat geschrieben:

Code: Alles auswählen

>>> x=str(0.3)
>>> type(x)
<type 'str'>
>>> y=float(x)
>>> type(y)
<type 'float'>
>>> 
>>> x
'0.3'
>>> y
0.29999999999999999
>>> 
Was soll das jetzt beweisen? Indem du float("0.3") ausführst, hast du wieder einen Float. Keinen String. Wenn du diesen am Interpreterprompt direkt anzeigen lässt (also via repr()), wird die Ungenauigkeit deutlich. Nochmal: Es gibt keine Möglichkeit für den Computer, die 0.3 als Float exakt zu speichern.
pyStyler
User
Beiträge: 311
Registriert: Montag 12. Juni 2006, 14:24

hmm ich will hier nichts beweisen! Nur bitte ich den Unterschied zwischen einen String und einer Dezimalzahl zumachen.

Code: Alles auswählen

>>> zahl=str(0.3)
>>> repr(zahl)
"'0.3'"
>>>
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

pyStyler hat geschrieben:hmm ich will hier nichts beweisen! Nur bitte ich den Unterschied zwischen einen String und eine Dezimalzahl zumachen.
Das ist ja auch löblich. Nur war das doch gar nicht das Thema.
pyStyler
User
Beiträge: 311
Registriert: Montag 12. Juni 2006, 14:24

birkenfeld hat geschrieben:
pyStyler hat geschrieben:hmm ich will hier nichts beweisen! Nur bitte ich den Unterschied zwischen einen String und eine Dezimalzahl zumachen.
Das ist ja auch löblich. Nur war das doch gar nicht das Thema.
naja wie auch immer ... Fakt ist das hier ein paar infos nicht ganz richtig waren.
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

pyStyler hat geschrieben:naja wie auch immer ... Fakt ist das hier ein paar infos nicht ganz richtig waren.
Solange jetzt nicht die meinst, auf die du mit "weiss nicht so genau was du damit meinst !" geantwortet hast... ;-)
pyStyler
User
Beiträge: 311
Registriert: Montag 12. Juni 2006, 14:24

meinst du vlt das hier >>> print float(a)
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Ohne Zusammenhang ist das für mich bedeutungslos.
Leto
User
Beiträge: 6
Registriert: Donnerstag 27. Juli 2006, 15:23

Sorry, aber noch hab ich nichts gerafft.
Das sind mir doch ein paar Aussagen zu viel (und scheinbar so widersprüchlich).

1. Mir ist schon klar, warum eine Zahl wie 0.3 binär nicht exakt dargestellt werden kann.
2. Mir ist auch klar warum das für z.b für 0.5 geht.
3. Mir ist ebenso klar, dass durch diese Ungenauigkeit ein Rechenfehler bei '0.3-01' auftritt, so dass das Ergebnis ungleich 0.2 ist.
4. Mir war nur eben nicht klar, warum str(0.3-0-1) auf einmal '0.2' ist.

Gut scheinbar wird da gerundet (das mit dem 'Nullen wegstreichen' war ja wohl überflüssig, immerhin reden wir von floatingpoint und nicht von fixedpoint).
Nur nach welchem System? An welcher Kommastelle? Woher weiß Python denn, wann gerundet werden soll und wann eine Zahl wie 0.19999999999999998 das tatsächlich erwartete Ergebnis darstellt?
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Code: Alles auswählen

>>> str(0.123456789123456789123456789)
'0.123456789123'
str rundet immer auf die gleiche Anzahl Nachkommastellen genau (nach obigem Beispiel scheinen es 12 Nachkommastellen zu sein).

Code: Alles auswählen

>>> 0.3
0.29999999999999999
>>> str(0.29999999999999999)
'0.3'
0.29999999999999999 auf 12 Stellen gerundet ist nunmal 0.300000000000 (wenn ich mich jetzt nicht verzaehlt habe). str() ist dann noch so schlau, die ueberfluessigen Nullen am Ende wegzulassen.

D.h. Python weiss ueberhaupt nichts von "exakt". Fuer den Computer sind diese Maschinenzahlen alle exakt.
Leto
User
Beiträge: 6
Registriert: Donnerstag 27. Juli 2006, 15:23

Na jetzt hab ichs (hoffentlich).

Wär mal interessant zu wissen, warum str denn an der 12 Stelle kürzt. Gibt es dafür irgendeinen logischen/technischen Hintergrund?
Antworten