ich brauche eine Funktion, welche zuverlässig abrundet und dabei auch mit float problemen (1.1+2.2 == 3.000000xxx) umgehen kann.
Ich hab natürlich schon nach abrunder funktionen gegoogelt und auch was gefunden, was aber leider nicht mit der float problematik umgehen kann. Deshalb habe ich es bis jetzt wie folgt modifiziert:
Code: Alles auswählen
def abrunder(zahl, schritt_weite):
zahl = float(zahl)
if zahl==0:
ergebnis = zahl
else:
original_schritt_weite = int(schritt_weite)
schritt_weite = round((1/10)**schritt_weite,original_schritt_weite) # dadurch kann man 1 fuer eine nachkommastelle und 2 fuer zwei stellen usw angeben
ergebnis = math.floor(round(zahl/schritt_weite,12))*schritt_weite # 0.58/0.1 sind leider 0.5799999... sobald bei round 15 anstatt 14 verwendet wird, rundet er falsch ... auch bei 14 kommt falsches runden vor -.-
ergebnis = repr(ergebnis)
zaehler = 0
for zeichen in ergebnis: # jedes zeichen dieser zahl durchgehen und . bzw , finden. und Position feststellen
if zeichen == "," or zeichen == ".":
break # sobald gebreaked wird, gibt zaehler die position des punktes an
zaehler += 1
if zaehler >= 1000:
raise AssertionError("Zeichenkette im Abrunder zu lang oder enthaelt kein , oder . ")
cut = int(zaehler+1+original_schritt_weite)
ergebnis = ergebnis[:cut] # bei 2 gewuenschten nachkommstellen ab der dritten zahl nach dem komma abtrennen, damit keine .0000001 kram bei rauskommt
ergebnis = float(ergebnis)
return (ergebnis)
1) Da wäre zum einen Decimal(), was aber tatsächlich um den Faktor 20 länger dauert, als wenn man mit float rechnet. Da ich sehr häufig abrunden muss, wäre das also eher keine option.
2) Anstatt mit 0.01 zu rechnen, mit 1 rechnen und so nachkommastellen vermeiden.
-> dies im ganzen skript anzuwenden würde einige Zeit dauern (das skript zu ändern) und wäre auch nicht optimal. Innerhalb der abrunder funktion wird ja bereits so gerechnet, indem diese schrittweite berechnet wird.. oder nicht?
Das Problem bei der aktuellen funktion ist einmal die Zeile:
ergebnis = math.floor(round(zahl/schritt_weite,12))*schritt_weite
das round() habe ich eingeführt, weil es vorkommt, dass übergebene zahlen, zb 1.14 dort zu 1.139999 werden, wodurch zahl/schritt_weite == 113.99999999999999 ist, was natürlich zu fehlern führt.
Gerade eben noch hatte diese ergebnis Zeile ein round() auf 14 stellen, anstatt 12. Aber ich musste leider feststellen, dass auch mit 14 manche zahlen, so auch die 1.14 falsch gerundet werden. Deswegen habe ich es jetzt auf 12 geändert... die Frage ist nur, ob das auch die endgültige Lösung ist, oder ob es noch andere Zahlen gibt, wo dies noch niedriger sein muss?
Und zusätzlich dann natürlich noch das Ergebnis selbst, welches potentiell ebenfalls x.0000000x sein kann.
Dort werden aktuell einfach nur alle stellen nach der gewünschten Nachkommastelle abgeschnitten, was bisher auch keine Probleme gemacht hat, also so funktioniert.
edit:
im falle von 1.14 will ich auf 2 nachkommastellen genau runden, dh. wenn ich 1.14 übergebe, soll er auch 1.14 zurückgeben.
würde es da also schon helfen, die zahl der nachkommastellen der übergebenen zahl zu anfang zu überprüfen, und wenn sie bereits 2 stellen hat, sie einfach wieder auszugeben, ohne veränderung ? Oder wuerde das nicht alle probleme lösen?
