Fehler bei Division / Rundung ?

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.
Kartoffel
User
Beiträge: 66
Registriert: Montag 7. April 2003, 17:08

Fehler bei Division / Rundung ?

Beitragvon Kartoffel » Mittwoch 16. April 2003, 12:57

Ich habe wieder mal ein Problem:

Code: Alles auswählen

>>> from __future__ import division
>>> 1/3
0.33333333333333331   #letzte Ziffer sollte 3 sein
>>> 2/3
0.66666666666666663   #letzte Ziffer sollte 6 sein
>>> round ((1/3),4)
0.33329999999999999   #sollte 0.3333 sein
>>> round ((2/3),2)
0.67000000000000004   #sollte 0.67 sein
>>>


Weiß jemand woran diese Rechen- und Rundungsfehler liegen und vor Allem wie ich die richtigen Ergebnisse bekomme?
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Beitragvon Milan » Mittwoch 16. April 2003, 13:23

Python hat keine gute interne Darstellung für Gleitkommazahlen. Desweegn existieren einige Gleitkommazahlen intern nicht und werden durch "anliegende" Zahlen ersetzt. Nicht die Optimale Lösung und recht nervig wenn man es genau haben will. (Ich hab mir deswegen extra mal ne Klasse zur Handhabung von Brüchen geschrieben, weil die ja wieder genau sind, solange es keine reelen Zahlen sein sollen). Mit dem Runden hat Python deswegen auch seine Probleme, zum Glück werden die Zahlen dann bei der Darstellung in strings exat angezeigt.

Wenn es dir also nur um die Anzeige von Floats geht, mach folgendes:

Code: Alles auswählen

erg=1/3.0
anzeige="%.2f"%erg

Das %f fügt nen Float in dne String ein und das .2 sag ihm, dass er zwei Nachkommastellen anzeigen soll.
Benutzeravatar
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Beitragvon hans » Donnerstag 17. April 2003, 20:07

Mal eine Zwischenfrage. Wären die Probleme in einem C Programm nicht die gleichen?

Egal wie genau man mit Floatingpoint Variablen rechnet, es belibt meistens ein Fehler, egal ob ich die Zahl mit 8, 16, 32, 64, 128 oder noch mehr Bits darstelle. Mit steigender Bitanzahl wird der Fehler kleiner. Die genaue Fehleberechnung möchte ich einem Mathematiker überlassen. Vielleicht fibdet sich ja hier mal einer.

Mit wieviel Bit rechnet Python bei Floatingpoint überhaupt?

Hans
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Beitragvon Voges » Donnerstag 17. April 2003, 20:26

hans hat geschrieben:Mal eine Zwischenfrage. Wären die Probleme in einem C Programm nicht die gleichen?

Ganz genau. Das Verhalten kann man wirklich nicht Python alleine anlasten. Im Tutorial der Doku gibt es den Anhang B "Floating Point Arithmetic: Issues and Limitations". Seeeeehr lesenswert. Zitat:
"Representation error refers to that some (most, actually) decimal fractions cannot be represented exactly as binary (base 2) fractions. This is the chief reason why Python (or Perl, C, C++, Java, Fortran, and many others) often won't display the exact decimal number you expect"
Jan
Kartoffel
User
Beiträge: 66
Registriert: Montag 7. April 2003, 17:08

Beitragvon Kartoffel » Freitag 18. April 2003, 09:53

Natürlich kann man keine Zahl unendlich genau berechnen, aber wenigstens richtige Rundungsergebnisse könnt man erwarten!

Wenn mir jemand eine Möglichkeit nennt, einzelne Dezimalstellen einer Zahl einzeln anzusprechen, könnte ich ja eine funktionierende Rundungsfunktion schreiben! (Und ich hab nun wirklich deutlich weniger Ahnung von sowas als die Leute, die Python geschrieben haben :lol: )
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Beitragvon Milan » Freitag 18. April 2003, 10:02

die würde dir aber auch nix bringen, weil sobald du einen Float benutzt, würde es wieder "ungenau" werden. Kannst es ja aber mal probieren. Du wandelst den Float in einen String um und im String kannst du jedes Zeichen einzeln abfragen.

Code: Alles auswählen

>>> a=str(3.456)
>>> a
"3.456"
>>> int (a[2])
4
Kartoffel
User
Beiträge: 66
Registriert: Montag 7. April 2003, 17:08

Beitragvon Kartoffel » Freitag 18. April 2003, 11:40

Code: Alles auswählen

>>> float("3.66")
3.6600000000000001

>>> 333/1000
0.33300000000000002


Das ist nicht mehr ungenau, das ist einfach nur falsch :x
Und in Cpp ist das Problem nicht da, da ist 1/3 noch 0.3333333 und die Welt ist in Ordnung :lol:
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Beitragvon Voges » Freitag 18. April 2003, 12:08

Hallo!
Kartoffel hat geschrieben:Das ist nicht mehr ungenau, das ist einfach nur falsch :x
Und in Cpp ist das Problem nicht da, da ist 1/3 noch 0.3333333 und die Welt ist in Ordnung

Wieso das? 0.3333333 ist doch viel ungenauer als Pythons 0.33333333333333331. Abgesehen davon, C/C++ rechnet exakt genauso wie Python.

Code: Alles auswählen

C/C++:
printf("\n%.30f",atof("3.66"));
printf("\n%.30f",333.0/1000);
printf("\n%.30f",1.0/3);
Python:
print "%.30f" % float("3.66")
print "%.30f" % (333./1000)
print "%.30f" % (1./3)

Ausgabe:
3.660000000000000100000000000000
0.333000000000000020000000000000
0.333333333333333310000000000000
3.660000000000000100000000000000
0.333000000000000020000000000000
0.333333333333333310000000000000

Jan
Kartoffel
User
Beiträge: 66
Registriert: Montag 7. April 2003, 17:08

Beitragvon Kartoffel » Freitag 18. April 2003, 12:35

Ich habe die Dezimalstellen nicht abgezählt, 0.33 =1/3 ist zwar nicht genauer als 0.3333331 aber es ist wenigstens richtig gerundet! Das wollte ich damit ausdrücken. Wie "genau" (Stellen) es wird hängt auch vom Dateityp ab...

Und bei mir gibt C++ es richtig aus.
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Beitragvon Voges » Freitag 18. April 2003, 13:07

Kartoffel hat geschrieben:Und bei mir gibt C++ es richtig aus.

Kannst da ein Code-Beispiel geben?
Jan
Kartoffel
User
Beiträge: 66
Registriert: Montag 7. April 2003, 17:08

Beitragvon Kartoffel » Freitag 18. April 2003, 13:13

Code: Alles auswählen

   cout << 1.0/3.0;
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Beitragvon Milan » Freitag 18. April 2003, 13:15

was aber dasselbe wäre wie str(1.0/3.0) oder print (1.0/3.0) in Python. Hier wird es wieder in nen String umgewandelt und das geht ja korrekt, wie ich oben schon gesagt habe.
kasimon
User
Beiträge: 18
Registriert: Freitag 21. März 2003, 20:54
Wohnort: Kiel

More KBytes

Beitragvon kasimon » Sonntag 27. April 2003, 10:13

Hi Leute,

1. hier findet ihr eine Seite mit dem bezeichnenden Namen
"What Every Computer Scientist Should Know About Floating Point Arithmetic",
vielleicht hilft euch das ja weiter.

2. Und lieber auf Papier liest, dem hilft vielleicht:
Randal E. Bryant and David R. O'Hallaron,
Computer Systems: A Programmer's Perspective (CS:APP),
Prentice Hall, 2003, ISBN 0-13-034074-X

Zumindest ist das genau das, was wir gerade in Rechnerorganisation durchnemhen.
Danach bestehen dann wirklich keine Fragen mehr.

3. Floating-Point Zahlen sind immer ungenau. Ist ja auch klar, mit einer endlichen Zahl von Bits
kann man auch nur eine endliche Anzahl von Zahlen darstellen.
Was problematisch zu sein scheint ist, dass

Code: Alles auswählen

>> 1.0/3.0
0.33333333333333331


ergibt, aber

Code: Alles auswählen

>>> print 1.0/3.0
0.333333333333


Die erste Zahl schein die interne genauigkeit zu sein, die zweite die angezeigte. Falls das so ist wie beim
Taschenrechner (da heißt es ja auch 8+2 oder 10+3 Stellen), dann gibt das erste die
berechneten Stellen an, das zweite die signifikanten, d.h. die Stellen, bei der sich Python
einigermaßen sicher ist, sich nicht verrechnet zu haben.

Vielleicht hilft's weiter. Ansonsten klingt mir das jetzt für einen Sonntag eindeutig zu sehr nach Uni :?

Gruss,

kasimon
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Re: More KBytes

Beitragvon Voges » Sonntag 27. April 2003, 13:00

Hallo!
kasimon hat geschrieben:Die erste Zahl scheint die interne genauigkeit zu sein,

Nein, die interne Genauigkeit ist wesentlich höher, zumindest was die Zahl der Stellen angeht. Der Wert, mit dem Python (und der Rechner selbst) intern arbeitet, lautet 0.333333333333333314829616256247.
Python ruft in bestimmten Fällen, z.B. für die Darstellung der Zahl implizit repr() auf und repr() selbst beschränkt sich auf 17 Stellen. Daher die 0.33333333333333331. str() beschränkt sich sogar nur auf 12 Stellen. Gerechnet wird aber immer mit dem obigen Monsterwert.
Ich verweise nochmal auf Anhang B des Tutorials: "Floating Point Arithmetic: Issues and Limitations". Müsste ja eigentlich jeder auf seinem Rechner haben ;-)
Jan

Nachtrag: Nonsens (von mir). Die Zahl der Stellen der internen Darstellung ist noch 'ne Ecke größer, also oben angegeben. Man sollte die Texte, die man anderen empfiehlt, auch selbst aufmerksam lesen :?
Zuletzt geändert von Voges am Sonntag 27. April 2003, 21:26, insgesamt 1-mal geändert.
Benutzeravatar
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Beitragvon hans » Sonntag 27. April 2003, 20:08

Danke Voges, besser kann man garnicht aufzeigen, wie super genau so ein Conputer rechnet. Und das reicht für Otto Normalverbraucher allemal. Wenn mir eine weis machen will , dass er mit dem Fehler nicht leben kann, z. B. weil der Kunde das nicht akzeptiert, dann ist da was ganz anderes faul, nur nicht die Gnauigkeit im PC. Aber mit einem IA64 kann man bestimmt Abhilfe schaffen.

Fragt sich nur, ob die Genauigkeitszunahme in Relation zu den Kosten steht. :shock:

Hans

Wer ist online?

Mitglieder in diesem Forum: Bing [Bot], egon11