![]() |
AW: System.Frac / System.Int / Math.SimpleRoundTo - komische Ergebnisse
Vermutlich lässt sich 9.0 nicht exakt im erforderlichen Type (Single, Double, Extended) unterbringen und es wird intern als 8.9999xxx dargestellt. Damit wird
Delphi-Quellcode:
zu 8 und
Trunc(9.0)
Delphi-Quellcode:
zu 0.9999xxx,was wiederum als 1.0 angezeigt wird.
Frac(9.0)
|
AW: System.Frac / System.Int / Math.SimpleRoundTo - komische Ergebnisse
Zitat:
Muss ich mir mal genauer anschauen - Danke für den Tipp! Zitat:
Ich glaube langsam wirklich, ich bleibe bei meinem Hack - der funktioniert nämlich ziemlich gut :) (ist aber natürlich wg. der Rumkonvertierererei von und nach String ziemlich langsam - spielt bei mir aber keine große Rolle) |
AW: System.Frac / System.Int / Math.SimpleRoundTo - komische Ergebnisse
Im Grunde liegt es wohl eher an Rundungsfehlern bei der Verwendung von Fließkommazahlen.
eine 0,9 könnte genau 0,9000000000 sein, aber wenn sich das nicht genau darstellen lässt oder es bei der Berechnung nicht ganz genau rauskommt, könnte es quasi 0,899999999999 aber auch 0,9000000000001 sein. (vereinfachtes Beispiel, damit man sieht, was ich meine) Und dann liefert es nachfolgend eben auch andere Werte, z.B. bei Trunc oder Int(0,899999999999 * 10) eben 8 anstatt 9. ![]() ![]() ![]() ... Bei mir geht's und es sind wirklich ganz genau 0,000000. (aber muß eben nicht) Double und Extended
Code:
type MyFloat = Double; //Extended;
procedure TForm25.FormCreate(Sender: TObject); procedure DebugLog(Val: MyFloat); begin var S := string.Create(' ', SizeOf(Val) * 2); BinToHex(@Val, PChar(S), Length(S)); // Val.Bytes[i] for 0..9 { knallt beim zweiten Durchlauf S := S + ' / ' + Val.ToString + ' / s' + Val.Sign.ToString + ' e' + Val.Exp.ToString + ' f' + Val.Frac.ToString; + ' / e' + Val.Exponent.ToString + ' f' + Val.Fraction.ToString + ' m' + Val.Mantissa.ToString } S := S + ' / ' + Val.ToString; S := S + ' / s' + Val.Sign.ToString; S := S + ' e' + Val.Exp.ToString; S := S + ' f' + Val.Frac.ToString; S := S + ' / e' + Val.Exponent.ToString; try S := S + ' f' + Val.Fraction.ToString; except S := S + ' peng'; end; // k.A. was es gegen 1/3 hat try S := S + ' m' + Val.Mantissa.ToString; except S := S + ' peng'; end; OutputDebugString(PChar(S)); end; var Val, Frac, Frac2: MyFloat; begin Val := 22.649; DebugLog(Val); // A01A2FDD24A63640 / 22,649 / s0 e1027 f1871527120149152 / e4 f1,4155625 m6375126747519648 Val := Val * 100; DebugLog(Val); // CDCCCCCCCCB1A140 / 2264,9 / s0 e1034 f476968144129229 / e11 f1,105908203125 m4980567771499725 Val := System.Int(Val); DebugLog(Val); // 0000000000B0A140 / 2264 / s0 e1034 f474989023199232 / e11 f1,10546875 m4978588650569728 Frac := System.Frac(Val); DebugLog(Frac); // 0000000000000000 / 0 / s0 e0 f0 / e0 f0 m0 Frac2 := Frac * 10.0; DebugLog(Frac2); // 0000000000000000 / 0 / s0 e0 f0 / e0 f0 m0 Frac2 := System.Int(Frac2); DebugLog(Frac2); // 0000000000000000 / 0 / s0 e0 f0 / e0 f0 m0 // auch komisch: Frac2 := Frac * 10.0; DebugLog(Frac2); // 0000000000000000 / 0 / s0 e0 f0 / e0 f0 m0 Frac2 := System.Frac(Frac2); DebugLog(Frac2); // 0000000000000000 / 0 / s0 e0 f0 / e0 f0 m0 Val := 1 / 3; DebugLog(Val); // 555555555555D53F / 0,333333333333333 / s0 e1021 f1501199875790165 / e-2 peng peng Val := 1 / 5; DebugLog(Val); // 9A9999999999C93F / 0,2 / s0 e1020 f2702159776422298 / e-3 f1,6 m7205759403792794 end; |
AW: System.Frac / System.Int / Math.SimpleRoundTo - komische Ergebnisse
Zitat:
|
AW: System.Frac / System.Int / Math.SimpleRoundTo - komische Ergebnisse
Zitat:
Zitat:
Delphi-Quellcode:
AMath.Frac(9.0) = 0.00000000000000E+0000
Zitat:
Delphi-Quellcode:
function Frac(const X: Extended): Extended;
begin Result := X - Int(X); end; |
AW: System.Frac / System.Int / Math.SimpleRoundTo - komische Ergebnisse
Zitat:
Delphi-Quellcode:
erhalte ich in beiden Fällen den exakt gerundeten Wert:
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;
Delphi-Quellcode:
System.Math.SimpleRoundTo(22.65, -1 ) = 2.27000000000000E+0001
SimpleRoundTo(22.65, -1 ) = 2.27000000000000E+0001 // lokale Kopie |
AW: System.Frac / System.Int / Math.SimpleRoundTo - komische Ergebnisse
Versuche mal das obige Beispiel ganz ohne Math.pas mit diesem Code:
Delphi-Quellcode:
function SimpleRoundTo(const AValue: Extended; const ADigit: TRoundToRange = -2): Extended;
var LFactor: Extended; begin LFactor := AMath.IntPower(10.0, ADigit); if AValue < 0 then Result := AMath.Int((AValue / LFactor) - 0.5) * LFactor else Result := AMath.Int((AValue / LFactor) + 0.5) * LFactor; end; |
AW: System.Frac / System.Int / Math.SimpleRoundTo - komische Ergebnisse
Es könnte natürlich auch sein, daß bei Dir die Rundungsart des Prozessors verstellt/falsch eingestellt ist. Bitte folgenden Code mal testen:
Delphi-Quellcode:
Es sollte rmNearest rauskommen! Das sollte eigentlich die Standard-Einstellung sein.
VAR
MyRoundingMode : TRoundingMode; MyRoundingModeStr: String; ... MyRoundingMode:= GetRoundMode; Case MyRoundingMode Of rmNearest: MyRoundingModeStr:= 'rmNearest'; rmUp: MyRoundingModeStr:= 'rmUp'; rmDown: MyRoundingModeStr:= 'rmDown'; rmTruncate: MyRoundingModeStr:= 'rmTruncate'; End; WriteLn('MyRoundingMode = ', MyRoundingModeStr); Falls nicht, kanns Du
Delphi-Quellcode:
verwenden.
SetRoundMode(rmNearest);
|
AW: System.Frac / System.Int / Math.SimpleRoundTo - komische Ergebnisse
Bei mir kommen unter Delphi 7 jedenfalls die erwarteten Ergebnisse heraus.
|
AW: System.Frac / System.Int / Math.SimpleRoundTo - komische Ergebnisse
Zitat:
Da kommt bei mir "rmNearest" zurück :wink: Ich bin meinen Code und v.a. meine Logging-Ausgaben nochmal durchgegangen - da war so einiges falsch. Durch die Ausgaben z.B. mit %f oder %.4f kamen einige bereits gerundete Ergebnisse zurück. Zudem war an manchen Stellen meine Ausgabe nicht synchron mit der tatsächlichen Berechnung (z.B. * 10 im Wert, im Text aber ohne * 10). Ich habe das jetzt alles mal korrigiert - der Wert, um den es dann ging war tatsächlich 22.648888888888 -> auf zwei Nachkommastellen dann ein Frac von 0.88888889 * 10 = 8.88888889 und hier ist Int() dann tatsächlich 8.00000 Ich habe allerdings immer noch den Fall, dass (angezeigt) aus Frac(9.0000000000) (1.00000000) wird - aber nur, wenn ich es innerhalb der Berechnung mit einer Variablen ausgebe. Wenn ich von Hand (als fest kodiert), den Wert 9.00000000 an die Frac-Routinen gebe, kommt korrekt 0.0 raus. Trotz allem sehr seltsam (0.00000001 oder so als Ergebnis würde ich ja noch verstehen, aber 1.00000000?) Zitat:
Zitat:
Wie dem auch sei - ich bin aktuell ganz zufrieden mit meinen Lösungen und Danke Euch allen für Eure Hilfestellungen! :thumb: |
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:57 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