Falsche Summe bei bestimmter Wertkombination

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.
Antworten
Zinober
User
Beiträge: 16
Registriert: Freitag 26. Dezember 2014, 15:58

Hallo,

ich habe ein seltsames Problem:
Um die Konsistenz einer Datenbanktabelle (SQLite) zu prüfen, berechne ich für jeden Datensatz die Summe der Einträge (float). Die sollte in jedem Fall 0 sein - sonst stimmt etwas mit den Daten nicht.

Das klappt bei knapp zweitausend Datensätzen auch problemlos. Bei einem Datensatz kommt aber ein mir völlig unverständliches Ergebnis heraus. Wenn ich einen beliebigen Wert in dem Datensatz ändere, wird richtig berechnet, aber genau bei dieser Wertkombination liefert mir das Skript einfach Quatsch.

Wenn jemand eine Idee hat, woran das liegen könnter oder einen Fehler in meinem Skript entdeckt, würde ich mich über einen Tipp freuen!

Code: Alles auswählen

zeile = cursor.fetchone()
while zeile:
	summe = zeile[3]
	if not summe:
		summe = 0
	summe = - summe
	for i in range(4,15):
		zahl = zeile[i]
		if not zahl:
			zahl = 0
		summe = summe + zahl
	if summe != 0:
		for i in range(3,15):
			print zeile[i]
		print "Summe: "+ str(summe)
		print"\n"
	zeile = cursor.fetchone()
liefert diese Ausgabe

Code: Alles auswählen

-4.2
None
None
None
None
None
-5.0
0.8
None
None
None
None
Summe: 2.22044604925e-16
Vielen Dank schon mal!
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@Zinober: Dir ist klar, was float für ein Datentyp ist? Falls nicht, hier die Erklärung: What Every Computer Scientist Should Know About Floating-Point Arithmetic. Das sollte Deine Frage beantworten.

PS: Das was Du da geschrieben hast, ist kein Python, auch wenn Python nicht meckert. Warum läßt Du Dir die Summe nicht von SQLite ausrechnen?

Code: Alles auswählen

for zeile in cursor:
    summe = sum(z or 0 for z in zeile[4:15]) - (zeile[3] or 0)
    if abs(summe) > 1e-14:
        for z in zeile[3:15]:
            print z
        print "Summe:", summe
Zinober
User
Beiträge: 16
Registriert: Freitag 26. Dezember 2014, 15:58

Hallo Sirius3,

danke erstmal für die schnelle Antwort!
Dir ist klar, was float für ein Datentyp ist?
Im Prinzip und grob theoretisch ja. Ich hätte aber tatsächlich nicht gedacht, daß das bei strukturell so einfachen Berechnungen auffällt. Ich werde den Artikel aber nochmal genauer durchschauen.
Das was Du da geschrieben hast, ist kein Python, auch wenn Python nicht meckert.
Deine Version hat defintitv mehr Flow. Keine Frage.
Bis ich sowas schreibe, brauch ich aber noch ein bißchen Übung.
Warum läßt Du Dir die Summe nicht von SQLite ausrechnen?
Ich kann SQL nun auch nicht besser als Python.

Danke nochmal für die Antwort und die Tipps!
BlackJack

@Zinober: Der falsche Wert der heraus kommt ist ja auch nicht so weit von 0 entfernt. Wenn man es mal ohne 10er-Exponent schreibt: 0.000000000000000222044604925.

Wie einfach die Rechnungen sind ist eigentlich egal denn das Problem sind ja nicht die Rechnungen sondern die begrenzte Genauigkeit von der internen Gleitkommarepräsentation. Und die Überraschung für viele die damit noch nicht konfrontiert waren, dass der Rechner in dieser Form so etwas scheinbar einfaches und genaues wie 0,1 nicht exakt speichern kann, sondern das mit 0.1000000000000000055511151231257827021181583404541 annähern muss.
Benutzeravatar
Humbalan
User
Beiträge: 59
Registriert: Mittwoch 2. September 2009, 15:11

hallo,

einfach gesagt: vermeide einen Vergleich auf Gleichheit bei floats. Es kommt oft nicht das Erwartete bei raus. Wenn es denn unbedingt notwendig ist, helfe ich mir mit

Code: Alles auswählen

if erwartet - tatsaechlicht < epsilon :
  print "ist gleich"
Wobei der Wert von epsilon vom aktuellen Problem abhängt und sehr klein sein muss im Vergleich mit den autretenden Zahlen. Vgl. http://de.wikipedia.org/wiki/Epsilontik.

Beste Grüße
Humbalan
BlackJack

@Humbalan: Ich würde da ja noch dringend ein `abs()` reinwerfen in die Rechnung. :-)
Benutzeravatar
Humbalan
User
Beiträge: 59
Registriert: Mittwoch 2. September 2009, 15:11

:oops:
Antworten