Mathefehler in Python?

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
Kidney
User
Beiträge: 2
Registriert: Dienstag 26. Mai 2020, 18:27

Servus Leute!
Ich habe angefangen Python zu lernen und bin auf etwas seltsames gestoßen.
Lange Rede kurzer Sinn. Seht selbst:

Code: Alles auswählen

print("can Python really calculate?", 2.4 * 6)
print("The result should be 14.40")

Python wirft als Ergebnis NICHT 14.40 aus, sondern 14.399999999999999.
Warum ist das so? Ist das nur auf meinem Rechner so?
Vielen Dank!

PS:
Anderer Test mit Unterhaltungswert:

Code: Alles auswählen

result = 2.4 * 6
if result == 14.40:
    print("Yes!")
else:
    print("Python: Es tut mir leid, ich war noch nie gut in Mathe.")
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das hat mit Python und deinem Rechner nichts zu tun. Das liegt an der Fliesskommazahlendarstellung nach IEEE754, die bei den meisten Computern und Programmiersprachen zum Einsatz kommt. Und die basiert zum einen auf dem binaersystem, und hat zum anderen eine begrenzte Genauigkeit. Und daher kommt es, das Zahlen, die im Dezimalsystem ganz leicht darstellen koennen, viel mehr Nachkommastellen brauchen. Und dadurch auch Rundungsfehler einfuehren.

Wenn man mit Fliesskommazahlen arbeitet, kann man darum (und auch aus vielen anderen Gruenden) ueblicherweise nicht mit == arbeiten, sondern muss den Vergleich mit einer gewissen Ungenauigkeit machen. Auch als Vergleich mit Epsilon bezeichnet:

Code: Alles auswählen

if abs(result - 14.40) < kleines_epsilon:
     print("ich bin ausreichend gut in Mathe")
Benutzeravatar
__blackjack__
User
Beiträge: 14052
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wobei das `math`-Modul da schon eine Funktion für hat:

Code: Alles auswählen

In [281]: import math                                                           

In [282]: math.isclose(2.4 * 6, 14.4)                                           
Out[282]: True
Und das Problem ist das 2.4 schon nicht exakt dargestellt werden kann. Sieht man, wenn man sich davon mal mehr Nachkommastellen anzeigen lässt:

Code: Alles auswählen

In [284]: format(2.4, ".50f")                                                   
Out[284]: '2.39999999999999991118215802998747676610946655273438'
Eine weitere Möglichkeit diese Ungenauigkeit auf Kosten von Rechenzeit zu umgehen ist das `decimal`-Modul:

Code: Alles auswählen

In [285]: from decimal import Decimal                                           

In [286]: Decimal("2.4") * 6 == Decimal("14.4")                                 
Out[286]: True
Oder man arbeitet mit Brüchen:

Code: Alles auswählen

In [288]: from fractions import Fraction                                        

In [289]: Fraction(24, 10)                                                      
Out[289]: Fraction(12, 5)

In [290]: Fraction(144, 10)                                                     
Out[290]: Fraction(72, 5)

In [291]: Fraction(24, 10) * 6                                                  
Out[291]: Fraction(72, 5)
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Benutzeravatar
snafu
User
Beiträge: 6867
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ich finde hier ja das schon erwähnte isclose() am hilfreichsten. Wenn einem das lieber ist, dann lässt sich der Funktion ein Alias vergeben:

Code: Alles auswählen

from math import isclose as is_equal

if is_equal(2.4 * 6, 14.4):
    print("Richtig gerechnet")
else:
    print("Falsch gerechnet")
Oder man "versteckt" den Aufruf hinter eine eigene Funktion:

Code: Alles auswählen

from math import isclose

def calc(calculation, result):
    if isclose(calculation, result):
        print("Richtig gerechnet")
    else:
        print("Falsch gerechnet")
Kidney
User
Beiträge: 2
Registriert: Dienstag 26. Mai 2020, 18:27

Wow, super! Vielen Dank für die Antworten! Wie komplex dann doch scheinbar einfache Gegebenheiten in der Informatik sein können :D
Antworten