AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Int und Frac schlecht bei Nachkommavergleichen
Thema durchsuchen
Ansicht
Themen-Optionen

Int und Frac schlecht bei Nachkommavergleichen

Ein Thema von Phoenix · begonnen am 3. Jul 2002 · letzter Beitrag vom 17. Okt 2002
Antwort Antwort
Benutzerbild von Phoenix
Phoenix
(Moderator)

Registriert seit: 25. Jun 2002
Ort: Hausach
7.606 Beiträge
 
#1

Int und Frac schlecht bei Nachkommavergleichen

  Alt 3. Jul 2002, 10:05
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
Sebastian Gingter
Phoenix - 不死鳥, Microsoft MVP, Rettungshundeführer
Über mich: Sebastian Gingter @ Thinktecture Mein Blog: https://gingter.org
  Mit Zitat antworten Zitat
jj-guitar

Registriert seit: 16. Okt 2002
4 Beiträge
 
#2
  Alt 17. Okt 2002, 10:44
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:
function FracEqual(x,y: double; Tolerance : double = 0.000001): boolean
begin
  Result := (Abs(x-y) < Tolerance);
end;
CU, jj
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:01 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz