![]() |
Int und Frac schlecht bei Nachkommavergleichen
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:
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.
function CheckFracValue(x, y : Real) : Boolean;
begin result := false; if ( frac(x) = y ) then result := true; end; 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:
liefert beispielsweise vollkommen falsch ein True zurück.
assert( Int(200204.02) + 0.02 <> 200204.02 );
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:
Wobei Decimals bei 2 Nachkommastellen 100 ist, bei 3 eben 1000 bzw. bei einer eben 10.
function CheckFracValue(x, y:real; decimals : integer) : boolean;
begin result := false; if ( round( (Int(x) + y) * decimals) = round( x * decimals)) ) then result := true; end; Andere Vorschläge dieses Problem zu lösen sind immer willkommen :) Bis denne, Sebastian |
Die Lösung ist schon OK.
Dass man real-Werte nicht auf Gleichheit prüfen darf, liegt an den Rundungsfehlern, die aufgrund der Speichergrenzen bei Rechenoperationen entstehen. Hier aber noch meine bevorzugte Lösung:
Code:
CU, jj
function FracEqual(x,y: double; Tolerance : double = 0.000001): boolean
begin Result := (Abs(x-y) < Tolerance); end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:40 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