![]() |
SimpleRoundTo
Ich habe schon die Fragen dazu im Forum gelesen, aber habe immer noch keine gute Antwort gefunden.
Ich benutze SimpleRoundTo, da ich kein kaufmännisches Runden haben möchte. Habe zwei Extended Werte a = 0.55 und b = 18.5. Das Produkt ist 10.175 müsste also mit SimpleRountTo(a*b, -2) aufgerundet werden auf 10.18. Im Debugger wird mir der Wert von Zitat:
Zitat:
Jetzt habe ich in der Math Bibliothek mal Trunc durch Round ersetzt und mit mrRoundnearest gerundet. Dann zeigt der Degugger: Zitat:
Zitat:
Zitat:
Ich will doch einfach nur einen "normal" gerundeten Wert haben. :evil: Wie erhalte ich hier den aufgerundeten Wert 10.18? |
AW: SimpleRoundTo
ich habe kein Problem mit:
Delphi-Quellcode:
aber vielleicht habe ich etwas falsch verstanden.
var
a,b,c:extended; begin a :=0.55; b := 18.5; c:=RoundTo(a*b,-2); Caption := FloatToStr(c); end; |
AW: SimpleRoundTo
Ich habe vor etlichen Jahren einen fiesen Bug in einer Abrechnungssoftware gehabt, aus ähnlichen Gründen.
Ich haben dann die Konstante 0.5 auf 0.5+1E-15 (also ein winzigkleinwenigmehr als 0.5) geändert. (Ich glaube zumindest, das es 1E-15 war, keine Ahnung) Zitat:
Delphi-Quellcode:
Trunc(unroundedValue/Granularity+0.5+1E-15)*Granularity
|
AW: SimpleRoundTo
Hallo,
ich kann Dein Problem mit dem Rundungfehler leider - noch nicht ganz - nachvollziehen. In Anlehnung an Bummis Beispiel ergibt sich bei mir für:
Delphi-Quellcode:
stets der Wert 10,18 (auch mit anderen Werten für a und b die entsprechend korrekte Rundung); also das, was Du eigentlich auch erwartest.
var
a, b : Extended; begin a := 0.55; b := 18.5; Caption := FloatToStr(SimpleRoundTo (a * b)) end; Gehe ich hingegen her und kopiere mir sozusagen den Code aus SimpleRoundTo und nehme:
Delphi-Quellcode:
erhalte ich das fehlerhafte Ergebnis 10,17. Für a, b, c : Double; erhalte ich korrekte Ergebnisse (SimpleRoundTo erwartet an der Stelle auch Double). Versuch' s doch mal mit Double für a und b.
var
f : Double; a, b, c : Extended; begin a := 0.55; b := 18.5; f := IntPower (10, -2); c := Trunc((a * b / f) + 0.5) * f; Caption := FloatToStr(c) end; Zitat:
Gruß |
AW: SimpleRoundTo
Das sollten klappen. Ob es schön ist, ist eine andere Frage.
Delphi-Quellcode:
Macht aus 12,34567 > 12,35
function MyRound(Value: Extended): Extended;
begin //bei 100 wird auf 2 Stellen gerundet, bei 1000 auf 3, usw. Result := Trunc(Value) + (Round(Frac(Value) * 100) / 100); end; Macht aus 12,34467 > 12,34 |
AW: SimpleRoundTo
Popov, bei deiner Lösung wird das Problem auch irgendwann auftreten.
Zitat:
|
AW: SimpleRoundTo
So wie Furtbichler habe ich es in der Vergangenheit auch gemacht.
Ich habe das Testprogramm von Bummi auch getestet und da funktioniert es. Die Daten kommen aber aus einer Firebird DB und sind TFibFloatFields. Aber ich habe alle Multiplikationen durch Int64 Multipilkationen ersetzt. Etwa so:
Delphi-Quellcode:
Damit berechne ich dann
Function Mult3(e1, e2, e3: Extended): Extended;
... i1 := Round(SimpleRoundTo(e1*1000), 0); i2 := Round(SimpleRoundTo(e2*1000), 0); ... Result := i1*i2*i3/1000000000; end;
Delphi-Quellcode:
Und dann wird 10,17 ausgegeben. Warum ist das unterschiedlich zu dem Code von Bummi?
Erg := Mult3(feld1, feld2, 1.0); // feld1 ist ein DB Feld mit Float Wert 0.55 und Feld2 mit 18.5;
Erg := SimpleRoundTo(erg, -2); |
AW: SimpleRoundTo
Zitat:
Ich glaube ich versuche einmal die Rundungsfunktionen hier ![]() |
AW: SimpleRoundTo
Die Floatingpointunit des Prozessors rechnet intern mit dem Typ Extended. Wenn die Zwischenergebnisse im Typ Double gespeichert werden, dann wird auf die geringere Auflösung gerundet (vergleichbar mit einem Taschenrechner der intern mit 12 Stellen rechnet in der Anzeige aber nur 10 Stellen darstellt). Solange ich innerhalb eines Typs bleibe (also Double oder Extended) ist das Endergebnis bei mir korrekt. Erst bei der Mischung der Typen kommt es zu sichtbaren Fehlern. Wenn also a,b vom Typ Extended sind, während f vom Type Double ist, ist der Fehler der Berechnung bei mir so groß, dass das Ergebnis der Rundung falsch ist.
Zitat:
Delphi-Quellcode:
Der Debugger (Delphi 2007/2010) zeigt a=10,175 an, obwohl der Fehler bereits bei 5E-10 liegt, und damit weit oberhalb der eigentlich erreichbaren Genauigkeit von Extended. Mir ist allerdings nicht klar, wie das Ergebnis von Mult3 in diesen Bereich kommen sollte. Ich habe mich redlich bemüht mit diesen Anfangswerten zu diesem Fehlerbild zu kommen - es klappt nicht.
var
a: Extended; begin a := 10.175 - 5E-10; Caption := FloatToStr(SimpleRoundTo(a)); Edit: Die Berechnung (a * b / f) + 0.5 ergibt einen Wert der etwas kleiner als 1018 ist (der Fehler sollte in etwa bei -2e-14 liegen). Bei der Zuweisung auf Double wird nun durch die Floatingpointunit auf 1018 gerundet. Das nachfolgende Trunc liefert dann den korrekten Integer 1018. Unterbleibt die Zuweisung auf Double und wird mit Extended weiter gerechnet, unterbleibt die prozessorinterne Rundung und trunc liefert den "falschen" Wert. Bei Delphi 2007 war die Funktion SimpleRoundTo wie folgt deklariert: function SimpleRoundTo(const AValue: Double; const ADigit: TRoundToRange = -2): Double; Bei Delphi 2009/2010 (spätere Versionen habe ich hier nicht) war es dann function SimpleRoundTo(const AValue: Extended; const ADigit: TRoundToRange = -2): Extended; Deshalb liefert die Funktion bei Delphi 2007 noch den korrekten Wert und bei Delphi 2009/2010 dann nicht mehr. |
AW: SimpleRoundTo
Volker Z. hat oben gepostet, wie er es nachbilden konnte.
Obwohl ich auch nicht verstehe warum der Effekt bei der Berechnung auftritt, habe ich (höchstwahrscheinlich) jetzt eine Funktion gefunden, die korrekt funktioniert. Es ist die Funktion DecimalRoundExt für Extended Values. Ich habe sie oben verlinkt und kann sie empfehlen, wenn jemand auch dieses nervige 1 Cent-Problem hat. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:16 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz