![]() |
Rundungsproblem in Delphi
Hallo
ich habe ein ganz seltsamens Rundungsproblem, das ich mit einer bestimmten Zahl festgestellt habe. Ich verwende folgenden Algorithmus zum Runden
Delphi-Quellcode:
Ich habe auch alle mögliche andere Vorschläge ausprobiert, aber keiner hat sicher geholfen.
function RoundToDecimals(rValue: Real; iDecimals: Integer): Real;
var Faktor, Wert: extended; iValue:Int64; begin Faktor := IntPower (10, iDecimals); Wert:= rValue * Faktor; if rValue > 0 then Wert := Wert + 0.5 else Wert := Wert - 0.5; iValue := trunc(Wert); // Hier zeigt Überwachte Ausdrücke iValue = 184132 und Wert = 184133 an Wert := iValue / Faktor; Result := Wert; end; Das Problem tritt nicht auf, wenn ich direkt RoundToDecimals(184.1325, 3) aufrufe.# Sobald ich die Zahl 184.1325 aber aus einem EditFeld per TryStrToFloat('184.1325', rValue) ermittle, habe ich das Problem Ich habe es auch mit Double und Extended probiert. Ohne Erfolg Ich weiß keine andere Zahl, wo das auftritt, muss aber sicherstellen, dass immer korrekt gerundet wird. Kann mir jemand sagen, woran das liegen könnte und wie ich es beheben kann. Ich verwende Delphi 7 Vielen Dank Gerd |
AW: Rundungsproblem in Delphi
Entgegen der allgemeinen Vorstellung, dass Trunc wirklich einfach abschneidet, rundet Trunc gegen "0". Bei unglücklicher Konstellation kann es dann zu solchen Phänomenen kommen.
Zum besseren Verständnis siehe ![]() |
AW: Rundungsproblem in Delphi
Hallöle...8-)
Zitat:
Zitat aus docwiki: "SimpleRoundTo ist das herkömmliche "Abrunden", das in der Schule gelernt wurde." Erklärung: ![]() ![]() Zitat:
|
AW: Rundungsproblem in Delphi
Hallo zusammen,
danke fürs Feedback. Zunächst muss ich sagen, dass mein Problem gelöst zu sein scheint. Ich habe auch in der Funktion die beiden Deklarationen
Delphi-Quellcode:
auf Real gesetzt. Hatte den Code hier aus DP kopiert und nur die Eingangsparameter an meine Werte angepasst.
Faktor, Wert: extended;
Trotzdem bin ich verwundert, dass sowohl in "Überwachte Ausdrücke" als auch wenn ich mit der Maus auf Wert fahre, genau 184133 angezeigt wird. Also keinerlei Kommastellen. Trotzdem kommt im Integer nach Trunc 184132 an Zitat:
Zitat:
Und in meinem Code multipliziere ich die Zahl ja sogar noch, sogar die gewünschten Stellen komplett ganze Zahlen sind und addiere dann noch 0.5 dazu. Trotzdem wird zum Schluss wieder abgerundet. Damit ist die Ganz-Zahl ja schon genau das, was ich will. Gewünscht ist eine kaufmännische Rundung. D.h. 184.1325 ergibt bei 3 Stellen 184.133 und 184.13249999 ergibt 184.132 |
AW: Rundungsproblem in Delphi
Zitat:
Hast du dir den Link angesehen? Dort wird nahezu das gleiche Problem dargestellt und Lösungen sind dort auch. |
AW: Rundungsproblem in Delphi
Zitat:
Aber jetzt habe ich hoffentlich wieder in Normalmodus geschalten. Hätte schon vorher passieren müssen. TRUNC schneidet ja nur ab => 184132.999999999999999999999999 wird zu 184132 :oops: Werden jetzt in die Formel noch Round(184132.9999) setzen und bin dann hoffentlich auf der sicheren Seite. |
AW: Rundungsproblem in Delphi
Leider bist du damit auch nicht auf der sicheren Seite.
Round verwendet das sogenannte Bankers Rounding. Dabei wird 3,5 zu 4 gerunden. Allerdings 4,5 auch zu 4. Das Prinzip dahinter: Bei x,5 wird zur nächsten geraden Zahl gerundet. Du brauchst SimpleRoundTo. Das müsste in der Unit System.Math stehen. Könnte bei D7 aber auch anders sein :wink: SimpleRoundTo macht es so, wie es bei uns in der Schule gelehrt wird. Bei x.5 wird aufgerundet. Und das passt dann auch zu deiner Anforderung. |
AW: Rundungsproblem in Delphi
D7 :gruebel:
ChatGPT sagt SimpleRoundTo für D7: Zitat:
Delphi-Quellcode:
Original D12:
// Beispielimplementierung von SimpleRoundTo in Delphi 7
function SimpleRoundTo(const AValue: Extended; const ADigit: Integer): Extended; var Factor: Extended; begin Factor := IntPower(10, ADigit); Result := Round(AValue * Factor) / Factor; end;
Delphi-Quellcode:
function SimpleRoundTo(const AValue: Extended; const ADigit: TRoundToRange = -2): Extended;
var LFactor: Extended; begin LFactor := IntPower(10.0, ADigit); if AValue < 0 then Result := Int((AValue / LFactor) - 0.5) * LFactor else Result := Int((AValue / LFactor) + 0.5) * LFactor; end; |
AW: Rundungsproblem in Delphi
Zitat:
Ich hatte die Funktion als Overload mit Extended und Double. Habe mittlerweile raus gefunden, dass Aufruf mit Extended korrekt auf 182.133 rundet, Aufruf mit Double aber auf 182.132. Das Programm in dem ich arbeite, arbeitet aber nahezu durchgängig mit Double und das umzustellen wäre ein ziemlicher Akt. Und wer weiß was da dann dafür passiert. Und natürlich ist die Umstellung von TRUNC auf ROUND auch nicht zielführend. Kann ja nicht zuerst 0.5 dazuaddieren und dann noch runden. Ich lasse es bei meinem "Bastelansatz" und der sieht bei Double jetzt so aus
Delphi-Quellcode:
Verwende das Ganze nur zum Runden von Dezimalen, und iDecimals wird immer nur positiv übergeben
function RoundToDecimals(rValue: Double; iDecimals: Integer): Double;
var rFactor: Double; begin rValue := rValue + 0.0000000000001; rFactor := IntPower(10.0, -iDecimals); if rValue < 0 then Result := Int((rValue / rFactor) - 0.5) * rFactor else Result := Int((rValue / rFactor) + 0.5) * rFactor; exit; end; Die 0.0000000000001 war der unterste Wert, der meine Wert so korrigiert hat, dass danach 184.133 raus kam. Egal wo ich die Funktion verwende, mehr als 10 Dezimalen werden nie angezeigt (Normal sind max 6). Die Erhöhung ist also nicht relevant Ach ja: Die D7 Formel kommt auch auf 184.132 |
AW: Rundungsproblem in Delphi
Es ist auch aus einem anderen Grund nicht ratsam auf Extended zu wechseln:
auf allen Plattformen außer Win32 wird Extended auf Double gemappt. Evtl. ist MacOS noch eine Ausnahme. Grund: Extended ist ein FPU interner Datentyp der x87 FPU. Die gibt's ja aber nicht überall und bei x64 wollte man lieber auf SSE Unterstützung (zumindest rudimentär) gehen. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:36 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