Hi,
mal keine Frage, sondern ein Hinweis für die Knowledge-Base hier
Problem:
Es kann unter Umständen wichtig sein, die Nachkommastelle einer Zahl auf einen Bestimmten Wert abzuprüfen.
Meine Erste Idee war folgendes:
Code:
function CheckFracValue(x, y : Real) : Boolean;
begin
result := false;
if ( frac(x) = y ) then
result := true;
end;
Normalerweise müsste der Aufruf CheckFracValue(200204.02, 0.02)
eigentlich true zurückliefern. Tut er aber nicht, da frac(200204.02) nicht 0.02 sondern 0.1999999999... zurückliefert.
Debugging im Assemblercode der native - Funktion von Delphi hat ergeben, das es durch die Gleitkommadarstellung bestimmte Nachkommawerte gibt, die nicht eineindeutig sind. So wird ,02 eben immer als ,0199... dargestellt. Das führt bei einem Vergleich, der auf Bitebene durchgeführt wird eben zu Unterschieden und damit zum falschen Ergebnis.
Die Funktion Frac(x: real) : real liefert deshalb zum Teil nicht unbedingt korrekte oder zumindest nicht unbedingt brauchbare Ergebnisse zurück. Gleiches tritt beim Int(x: real) : real - Aufruf auf, der nur den Vorkommaanteil einer Zahl zurückliefert:
Code:
assert( Int(200204.02) + 0.02 <> 200204.02 );
liefert beispielsweise vollkommen falsch ein True zurück.
Lösung:
Der Vergleich darf nicht auf der Nachkommaebene, sondern vor dem Komma durchgeführt werden, und zwar nicht mit Gleitkommazahlen sondern anhand von Integerwerten.
Code:
function CheckFracValue(x, y:real; decimals : integer) : boolean;
begin
result := false;
if ( round( (Int(x) + y) * decimals) = round( x * decimals)) ) then
result := true;
end;
Wobei Decimals bei 2 Nachkommastellen 100 ist, bei 3 eben 1000 bzw. bei einer eben 10.
Andere Vorschläge dieses Problem zu lösen sind immer willkommen
Bis denne,
Sebastian