Falsche Ergebnisse mit round()

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
Pykons
User
Beiträge: 11
Registriert: Dienstag 14. Februar 2017, 09:45

Hallo an alle! :D

Ich arbeite jetzt seit knapp einem halben Jahr mit Python und bisher mache ich (eigentlich) gut und schnell Fortschritte und bin von Python begeistert!
Während ich ein neues Programm geschrieben habe bin ich nun auf folgendes Problem gestoßen, was ich mir nicht erklären und auch leider nicht lösen kann:

Die Funktion round() rundet bei mir nicht immer ab 5 auf, sondern gerne auch mal ab. Habe dazu mal ein kurzes Testprogramm geschrieben, das mein Problem verdeutlichen soll:

Code: Alles auswählen

i=50
while i<=1000:
    print(str(i)+"\t-->\t"+str(round(i,-2)))
    i=i+100
Als Ergebnis bekomme ich:
  • 50 --> 0
    150 --> 200
    250 --> 200
    350 --> 400
    450 --> 400
    550 --> 600
    650 --> 600
    750 --> 800
    850 --> 800
    950 --> 1000
Nehmen wir z.B. die Werte 150 und 250. Bei 150 rundet Python brav auf 200 auf, allerdings bei 250 nicht auf 300 auf, sondern auf 200 ab.
Hat jemand eine Idee, woran das liegen könnte? Und vor allem, wie kann ich das beheben? :K

(Ich arbeite mit Python 3.5.3, habe extra grad nochmal Python upgedatet, um ausschließen zu können, dass es an einer veralteten Version liegt...allerdings ohne Erfolg)

Vielen Dank schonmal für eure Hilfe!!
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Pykons hat geschrieben:Nehmen wir z.B. die Werte 150 und 250. Bei 150 rundet Python brav auf 200 auf, allerdings bei 250 nicht auf 300 auf, sondern auf 200 ab.
Hat jemand eine Idee, woran das liegen könnte? Und vor allem, wie kann ich das beheben?
Das kannst Du nicht beheben, da dies ein Feature ist, das mit Python 3.5 eingeführt wurde. Gerundet wird alternierend stets auf die nächste gerade Zahl. Dieses Vorgehen kommt aus der Finanzbranche und dient dazu, bei der Akkumulation von gerundeten Werten den Gesamtfehler möglichst gering zu halten.
Pykons
User
Beiträge: 11
Registriert: Dienstag 14. Februar 2017, 09:45

Hallo kbr, danke für die schnelle Antwort!

Hab das Problem jetzt für mich soweit umgangen:

Code: Alles auswählen

i=50
while i<=1000:
    if i%100==50:
        print(str(i)+"\t-->\t"+str(i+50))
    else:
        print(str(i)+"\t-->\t"+str(round(i,-2)))
    i=i+100
Das funktioniert für meinen Anwendungsfall gut. Allerdings frage ich mich jetzt grade, ob es in Python noch eine weitere Funktion neben round() gibt, die mathematisch korrekt rundet und eben nicht wirtschaftsmathematisch (wenn man das so sagen kann)...?!

Und wann rundet round() auf und ab? Steckt dahinter ein Prinzip, oder ist das reiner Zufall, ob bei 150 auf 200 oder 100 gerundet wird?
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@Pykons: was richtiges Runden ist, ist eben Definitionssache. Das Runden, das man aus der Schule kennt, hat eben unschöne Eigenschaften: gerundete Zahlen sind, statistisch gesehen, größer. Das bessere Runden heißt, zur nächsten geraden Zahl runden; so weder statistisch gesehen die Hälfte der Zahlen größer und die andere Hälfte kleiner. Die Frage ist also, warum Du unbedingt auf dieses unschöne Runden beharren willst.
BlackJack

Zum warum und warum das nicht falsch ist: Die Dokumentation zu `round()` dokumentiert das Verhalten ausdrücklich so und dann sollte sich die Funktion auch wirklich so Verhalten. Sonst wär's ein Bug. :-)
Pykons
User
Beiträge: 11
Registriert: Dienstag 14. Februar 2017, 09:45

Sirius3 hat geschrieben:Die Frage ist also, warum Du unbedingt auf dieses unschöne Runden beharren willst.
Ich möchte einen Graphen plotten, dazu bestimme ich den maximalen Y-Wert und möchte den aufrunden, um die Y-Achse sauber zu beschriften. Daher reicht meine Lösung, wie oben beschrieben, auch vollkommen aus und ich löse das "Problem" auf meine Weise. Wollte aber für zukünftige Berechnungen in Python einfach mal erfragen, weshalb round() die besagten Ergebnisse ausspuckt.
BlackJack hat geschrieben:Die Dokumentation zu `round() dokumentiert das Verhalten ausdrücklich so und dann sollte sich die Funktion auch wirklich so Verhalten. Sonst wär's ein Bug. :-)
Da hast du recht, die hatte ich nicht gelesen. Bisher habe ich immer mit einem Buch gelernt und dort recherchiert. Dort war nur von "runden" die Rede, daher meine Annahme, dass es sich um das Runden, was man aus der Schulzeit kennt, handeln würde. :D
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@Pykons: wenn Du immer aufrunden möchtest, dann willst Du vielleicht `math.ceil` verwenden.
Pykons
User
Beiträge: 11
Registriert: Dienstag 14. Februar 2017, 09:45

Das Problem ist aber, dass ich die zweite Stelle vor dem Komma runden möchte. Also beispielsweise von 350 auf 400. Ich kann bei ceil im Gegensatz zu round aber nur ein Argument angeben. Den Vorteil, den ich bei round gesehen habe war, dass ich auch angeben kann, auf welche Stelle ich runden möchte - also:

Code: Alles auswählen

round(350,-2)
Oder geht das bei ceil auch und ich hab es bisher einfach nicht geschnallt/richtig gemacht?
BlackJack

@Pykons: Man muss halt noch ein bisschen rechnen wenn man `ceil()` verwendet. Kann man ja in einer eigenen Rundungsfunktion ”verstecken”.
Benutzeravatar
pixewakb
User
Beiträge: 1408
Registriert: Sonntag 24. April 2011, 19:43

BlackJack hat geschrieben:Kann man ja in einer eigenen Rundungsfunktion ”verstecken”.
In dem Fall würde ich direkt eine eigene Rundungsfunktion schreiben, die fas für mich sinnvoll löst...
Antworten