Seite 1 von 1
Wieder mal Runden von Float
Verfasst: Mittwoch 4. Juni 2014, 15:20
von Hase
Hallo,
wie bekomme ich es hin, dass der Grenzfall
zu 4.1 und nicht zu 4.0 gerundet wird. Mit round() bin ich sonst ganz zufrieden, sonst tut es genau das, was es soll. Ich habe mir auch
"Floating Point Arithmetic: Issues and Limitations" duchgelesen. Jetzt weiß ich zwar, warum es nicht immer klappt. Es steht aber leider nicht da, wie ich das Problem umschiffen kann.
Das Ganze gehört zu einem ziemlich komplexen Programm und ich möchte vermeiden, größere Teile komplett neu zu schreiben. Ich suche also eine einfache, sichere und wirkungsvolle Lösung.
Danke
I.H.
Python 2.7
The behavior of round() for floats can be surprising
Re: Wieder mal Runden von Float
Verfasst: Mittwoch 4. Juni 2014, 15:55
von Boa
Eine Möglichkeit wäre eine Ungenauigkeit miteinzubeziehen und den Fall X.X5 separat zu behandeln. Vermutlich gibt es eine einfachere Lösung
Code: Alles auswählen
from decimal import Decimal
dec = Decimal(4.05)+Decimal(0.000001) # Ungenauigkeit von einer Promille berücksichtigen
to_round = int(dec*Decimal(100)) # Zu Ganzzahl konvertieren
if to_round % 10 == 5: # um zu sehen ob sie mit dem Spezialfall 5 endet
rounded = round((to_round + Decimal(5)) / Decimal(100), 1) #Addiere 0,05 um sicher zu gehen, dass aufgerundet wird
else:
rounded = round(dec) # Ansonsten normal runden
Re: Wieder mal Runden von Float
Verfasst: Mittwoch 4. Juni 2014, 16:17
von EyDu
@Boa: Du beziehst keine Ungenauigkeit mit ein, sondern fügst nur noch weitere hinzu. Unter Umständen werden die Berechnungen sogar fehlerhaft.
Hase hat geschrieben:Ich habe mir auch "Floating Point Arithmetic: Issues and Limitations" duchgelesen. Jetzt weiß ich zwar, warum es nicht immer klappt. Es steht aber leider nicht da, wie ich das Problem umschiffen kann.
Doch, das steht da. Es wird auf das decimal-Modul hingewiesen, mit dem du solche Probleme umgehen kannst.
Hase hat geschrieben:Das Ganze gehört zu einem ziemlich komplexen Programm und ich möchte vermeiden, größere Teile komplett neu zu schreiben. Ich suche also eine einfache, sichere und wirkungsvolle Lösung.
Du wirst nichts neu schreiben müssen, das Durchgehen deines gesamten Codes wird allerdings nötig sein. Wenn du die von dir gewünschten Garantien haben willst, dann musst du alle Vorkommnisse von ``float``s durch ``decimal.Decimal`` ersetzen. Sonst werden auch alle Zwischenschritte fehlerhaft berechnet. Ich hoffe, dass du gute und ausreichend viele Unit-Tests hast, sonst kann das ekelhaft werden

Re: Wieder mal Runden von Float
Verfasst: Mittwoch 4. Juni 2014, 16:28
von cofi
Na, wenn man schon mal `decimal` einbringt, kann man es auch direkt zum Runden benutzen und damit mehr Kontrolle zu haben _wie_ gerundet wird.
Vorausgesetzt du willst bei 5 immer aufrunden:
Code: Alles auswählen
In [14]: import decimal
In [15]: d = decimal.Decimal('4.05')
In [16]: d.quantize(decimal.Decimal('0.1'), rounding=decimal.ROUND_HALF_UP)
Out[16]: Decimal('4.1')