Code: Alles auswählen
f"{2.635:.20f}"
# 2.63499999999999978684
Code: Alles auswählen
f"{2.635:.20f}"
# 2.63499999999999978684
Code: Alles auswählen
from decimal import Decimal, localcontext, ROUND_HALF_UP
def wechselgeld(betrag: str, münzen: list[Decimal]):
with localcontext(rounding=ROUND_HALF_UP):
betrag = round(Decimal(betrag), 2)
münzen = sorted(münzen, reverse=True)
ergebnis = {}
for münze in münzen:
menge = betrag // münze
betrag -= münze * menge
ergebnis[münze] = int(menge)
return ergebnis, betrag
münzen = [Decimal(s) / 100 for s in (1, 2, 5, 10, 20, 50, 100, 200)]
ergebnis, rest = wechselgeld("13.367", münzen)
# wir aufgerundet auf 13.37
summe = sum(value * amount for value, amount in ergebnis.items())
print("Münzen:", münzen)
print("Rest:", rest)
print("Wechselgeld:", ergebnis)
print("Summe:", summe, "Typ:", type(summe))
Jup, wobei ja auch diese Float-Darstelllung so nur max. auf 8 Stellen genau sein sollte.Sirius3 hat geschrieben: ↑Montag 29. Januar 2024, 14:57 @Qubit: Dezimalzahlen können nicht immer exakt durch binäre Floats dargestellt werden, 2.635 ist in WirklichkeitUnd damit kleiner als 2.635 und wird deshalb abgerundet.Code: Alles auswählen
f"{2.635:.20f}" # 2.63499999999999978684
Code: Alles auswählen
round_float = lambda number, prec=0: round(round(10**prec*number,1))/10**prec
zahl = 2.635
print(round_float(zahl,2))
print(round_float(zahl,20))
print(round_float(zahl,200))
2.64
2.635
2.635
Was heisst näher?
Verstehe da jetzt leider nicht ganz was du meinst, welche Rundung genau?Sirius3 hat geschrieben: ↑Montag 29. Januar 2024, 22:26 @qubit: Deine Rundung ist aber falsch, wenn ich die Zahl 2.63499999999999978684 runden möchte, wird fälschlicherweise aufgerundet.
Du hast nur den einen nummerischen Fehler durch einen anderen ersetzt. Zum Glück ist klar definiert, wie gerundet werden sollte, und das ist nicht die Näherungsformel, die Du erfunden hast, weil dessen Fehler zu groß ist.
Code: Alles auswählen
round_float = lambda number, prec=0: round(round(10**prec*number,1))/10**prec
zahl = 2.63499999999999978684
print(f"{round_float(zahl,19):.19f}")
print(f"{round(zahl,19):.19f}"
2.6349999999999997868
2.6349999999999997868
Doch "2.635" ist eine reelle Zahl.
Naja, nur weil es "dokumentiert" ist, ist es noch nicht von Fehlerhaftigkeit befreit (die Anforderungen zählen).nezzcarth hat geschrieben: ↑Montag 29. Januar 2024, 23:38 @Qubit: Das Verhalten, das du bemängelst, wird in der Doku von round explizit angesprochen und wie von Sirius3 und narpfel beschrieben erklärt (https://docs.python.org/3/library/functions.html#round). Daher würde ich das nicht als Fehler sehen. Der Begriff "wissenschaftliches Runden" taucht in der Doku übrigens nicht auf; den hatte ich nur angeführt, man sollte sich jedoch nicht dran aufhalten.
Sorry, ich weiss nicht genau, was du mir erklären willst?narpfel hat geschrieben: ↑Montag 29. Januar 2024, 23:39 @Qubit: In Python eben nicht. Da gibt es keine reellen Zahlen. Kann es auch gar nicht, weil man im allgemeinen Fall nicht wirklich damit rechnen kann. Unter anderem, weil fast alle reellen Zahlen nicht berechenbar sind (es kann also keine Turing-Maschine (und damit auch kein Python-Programm) geben, das die Zahl berechnet). Außerdem sind fast alle reellen Zahlen nichtmal definierbar.
Im Kontext von Programmiersprachen muss man damit immer mit Untermengen der reellen Zahlen rechnen. Und da ist 2.635 eben eine 64-Bit-IEEE-754-Zahl. Wenn man eine andere Untermenge (mit eventuell anderen arithmetischen Eigenschaften) haben will, gibt es z. B. `decimal.Decimal` für Dezimalzahlen mit beliebiger (endlicher) Präzision oder `fractions.Fraction` für rationale Zahlen.
Das kann man natürlich so sehen.Dennis89 hat geschrieben: ↑Montag 29. Januar 2024, 23:53 `round` würde versagen, wenn sich `round` anders verhalten würde als in der Doku beschrieben. Da aber beschrieben ist, was `round` kann und wie es sich in bestimmten Fällen verhält, ist es dann Anwendersache, die für seine Ansprüche richtige Funktion auszusuchen.
Code: Alles auswählen
In [27]: math.sqrt(2) ** 2
Out[27]: 2.0000000000000004
In [28]: math.sqrt(2) ** 2 == 2.0
Out[28]: False
Hm, ich bin ehrlich gesagt im Zweifel, ob du wirklich Ahnung hast, worüber du sprichst..narpfel hat geschrieben: ↑Dienstag 30. Januar 2024, 00:22 @Qubit: Wie willst du einen Datentyp für reelle Zahlen definieren, wenn fast alle reellen Zahlen nicht berechenbar sind? Also wirklich für reelle Zahlen und nicht für irgendeine Untermenge? Wenn das nicht geht, dann ja, man kann mit Computern nicht richtig runden. Unter anderem, weil man fast alle Zahlen nichtmal darstellen kann.
Die reelle Zahl 2,635 ist nicht exakt als `float` darstellbar. Mit dem Datentyp `float` ist es also prinzipiell unmöglich, sie „korrekt“ (nach deiner Definition) zu runden. Weil 2,635 eben keine `float`-Zahl ist.
Ist `math.sqrt` auch inkorrekt?Code: Alles auswählen
In [27]: math.sqrt(2) ** 2 Out[27]: 2.0000000000000004 In [28]: math.sqrt(2) ** 2 == 2.0 Out[28]: False
Sorry, ich glaube, wie sprechen auch einander vorbei..
Code: Alles auswählen
von
>>> f"{2.635:.20f}"
'2.63499999999999978684'
mit Rundungsalgorithmus
nach
>>> f"{2.64:.20f}"
'2.64000000000000012434'
Code: Alles auswählen
>>> f"{2.63:.20f}"
'2.62999999999999989342'