Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Vergleich von Real-Werten ---> klappt nicht (https://www.delphipraxis.net/146817-vergleich-von-real-werten-klappt-nicht.html)

markus5766h 27. Jan 2010 12:00


Vergleich von Real-Werten ---> klappt nicht
 
Hallo,

nachfolgend der problematische Code:
Delphi-Quellcode:
Const
 E96  : array[1..98] of Real =
  (0, 1.0, 1.02, 1.05, 1.07, 1.1, 1.13, 1.15, 1.18, 1.21, 1.24, 1.27, 1.30, 1.33,
   1.37, 1.40, 1.43, 1.47, 1.50, 1.54, 1.58, 1.62, 1.65, 1.69, 1.74, 1.78, 1.82,
   1.87, 1.91, 1.96, 2.0, 2.05, 2.1, 2.15, 2.21, 2.26, 2.32, 2.37, 2.43, 2.49, 2.55,
   2.61, 2.67, 2.74, 2.80, 2.87, 2.94, 3.01, 3.09, 3.16, 3.24, 3.32, 3.40, 3.48,
   3.57, 3.65, 3.74, 3.83, 3.92, 4.02, 4.12, 4.22, 4.32, 4.42, 4.53, 4.64, 4.75,
   4.87, 4.99, 5.11, 5.23, 5.36, 5.49, 5.62, 5.76, 5.90, 6.04, 6.19, 6.34, 6.49,
   6.65, 6.81, 6.98, 7.15, 7.32, 7.50, 7.68, 7.87, 8.06, 8.25, 8.45, 8.66, 8.87, 9.09,
   9.31, 9.53, 9.76, 10);

......

implementation

 var
 Rv : Real;


// Rv ist 634


  for i := 2 to 98 do
    if Rv = (E96[i-1] * multi) then // <<<<< wird nicht erkannt !!!!!!!!!!
     begin
      lb96Min.Caption := FloatToStr(E96[i-1] * multi) + ' Ohm';
      lb96Max.Caption := '';
      break;
     end;

   // <<<<< hier bekomme ich 634 und 649 zurück
   for i := 1 to 98 do
    if (Rv > E96[i-1] * multi) and (Rv < E96[i] * multi) then
     begin
      lb96Min.Caption := FloatToStr(E96[i-1] * multi) + ' Ohm';
      lb96Max.Caption := FloatToStr(E96[i] * multi) + ' Ohm';
      break;
     end;
mehrmals nachgerechnet : Rv ist genau 634
multi ist ein Multiplikator, Typ Integer, hier 100

warum wird der direkte Vergleich nicht erkannt ? :gruebel:

himitsu 27. Jan 2010 12:04

Re: Vergleich von Real-Werten ---> klappt nicht
 
Das nennt man Rundungsfehler, welchen diese Fließkommatypen unterliegen.
Diese Typen können keine beliebigen Zahlen darstellen, sondern nur einen "kleinen" Teil der reellen Zahlen.

Darum darf/kann man auch nicht genau auf = prüfen.

guinnes 27. Jan 2010 12:05

Re: Vergleich von Real-Werten ---> klappt nicht
 
Dann wird sich 6.34 nicht 100%ig als Real darstellen lassen. Du solltest beim vergleich eine Bandbreite zulassen

Mithrandir 27. Jan 2010 12:08

Re: Vergleich von Real-Werten ---> klappt nicht
 
Delphi-Quellcode:
Int(Rv) = (E96[i-1] * multi)
Kann nicht funktionieren, da beide intern nicht gleich aussehen, auch wenn du den Real nach Int castest. Als Workaround spontan das hier:
Delphi-Quellcode:
If Abs(RV - (E96[i-1] * multi)) < eps then
wobei eps in diesem Falle eine Konstante ist, die die Genauigkeit angiebt, bspw.

Delphi-Quellcode:
const
eps = 0.001; //<> 1E-3
Wobei es vermutlich auch noch andere Ansätze gibt...

markus5766h 27. Jan 2010 12:13

Re: Vergleich von Real-Werten ---> klappt nicht
 
Zitat:

Zitat von guinnes
Dann wird sich 6.34 nicht 100%ig als Real darstellen lassen. Du solltest beim vergleich eine Bandbreite zulassen

... das kann's eigentlich nicht sein : hab's auch mit
Delphi-Quellcode:
 if Trunc(Rv) = Trunc(E96[i-1] * multi) then ...
versucht; hier müsste es dann eigentlich funktionieren !?

markus5766h 27. Jan 2010 12:17

Re: Vergleich von Real-Werten ---> klappt nicht
 
Zitat:

Zitat von Daniel G
Delphi-Quellcode:
Int(Rv) = (E96[i-1] * multi)
Kann nicht funktionieren, da beide intern nicht gleich aussehen, auch wenn du den Real nach Int castest. Als Workaround spontan das hier:
Delphi-Quellcode:
If Abs(RV - (E96[i-1] * multi)) < eps then
wobei eps in diesem Falle eine Konstante ist, die die Genauigkeit angiebt, bspw.

Delphi-Quellcode:
const
eps = 0.001; //<> 1E-3
Wobei es vermutlich auch noch andere Ansätze gibt...

das Int(Rv) ist schon wieder raus ... war nur ein Versuch.
mit
Delphi-Quellcode:
 If Abs(RV - (E96[i-1] * multi)) < eps then ...
funktionierts. Danke

Luckie 27. Jan 2010 12:18

Re: Vergleich von Real-Werten ---> klappt nicht
 
Eventuell trägt das: http://www.michael-puff.de/Artikel/Fliesskomma.shtml zum Verständnis bei.

markus5766h 27. Jan 2010 12:23

Re: Vergleich von Real-Werten ---> klappt nicht
 
Zitat:

Zitat von Luckie
Eventuell trägt das: http://www.michael-puff.de/Artikel/Fliesskomma.shtml zum Verständnis bei.

o.k. aufgefrischt .... :thumb:

Dezipaitor 27. Jan 2010 13:36

Re: Vergleich von Real-Werten ---> klappt nicht
 
Zitat:

Zitat von Daniel G
Delphi-Quellcode:
Int(Rv) = (E96[i-1] * multi)
Kann nicht funktionieren, da beide intern nicht gleich aussehen, auch wenn du den Real nach Int castest. Als Workaround spontan das hier:
Delphi-Quellcode:
If Abs(RV - (E96[i-1] * multi)) < eps then
wobei eps in diesem Falle eine Konstante ist, die die Genauigkeit angiebt, bspw.

Delphi-Quellcode:
const
eps = 0.001; //<> 1E-3
Wobei es vermutlich auch noch andere Ansätze gibt...

Huch, das ist kein Workaround, das ist DER Lösungsweg, wie man Werte vergleicht, die vom Computer nicht exakt dargestellt werden können: Epsilonumgebung.
Sei nicht so bescheiden :P

Mithrandir 27. Jan 2010 13:53

Re: Vergleich von Real-Werten ---> klappt nicht
 
Zitat:

Zitat von Dezipaitor
nicht so bescheiden :P

*hust* Ok... :oops:

alex517 27. Jan 2010 14:28

Re: Vergleich von Real-Werten ---> klappt nicht
 
nach dem man die Theorie verstanden hat, :-D
kann man es sich auch leichter machen und auf vorhandene
Funktionen zugreifen wie z.B.:

Delphi-Quellcode:
uses Math;

function SameValue(..)
function IsZero(..)
function CompareValue(..)

...
alex


Edit:
Delphi-Quellcode:
function SameValue(const A, B: Single; Epsilon: Single = 0): Boolean; overload;
function SameValue(const A, B: Double; Epsilon: Double = 0): Boolean; overload;
function SameValue(const A, B: Extended; Epsilon: Extended = 0): Boolean; overload;

function IsZero(const A: Single; Epsilon: Single = 0): Boolean; overload;
function IsZero(const A: Double; Epsilon: Double = 0): Boolean; overload;
function IsZero(const A: Extended; Epsilon: Extended = 0): Boolean; overload;

function CompareValue(const A, B: Integer): TValueRelationship; overload;
function CompareValue(const A, B: Int64): TValueRelationship; overload;
function CompareValue(const A, B: Single; Epsilon: Single = 0): TValueRelationship; overload;
function CompareValue(const A, B: Double; Epsilon: Double = 0): TValueRelationship; overload;
function CompareValue(const A, B: Extended; Epsilon: Extended = 0): TValueRelationship; overload;
@Medium, #12: so besser?

Medium 27. Jan 2010 14:55

Re: Vergleich von Real-Werten ---> klappt nicht
 
Wobei diese Funktionen durchaus mit Vorsicht zu genießen sind, wenn mit den Werten zuvor sehr viel herumgerechnet wird. Wenn es meinetwegen um die Nte (groooßes N) Iteration einer konvergierenden Reihe geht, und das Ergbnis mit dem erwarteten Grenzwert werglichen werden soll, kann es sein dass das in diesen Funktionen verwendete Epsilon (IMHO ist es das sog. Maschinen-Epsilon) zu klein wird.
Der Vergleich hinkt, da eine Reihe ja per Definition schon nur eine Näherungsfunktion ist, das ganze trifft aber generell zu. Je mehr Operationen ich verwendet habe um zu einem Wert zu kommen, desto heftiger haben sich dabei diese Darstellungfehler aufsummiert, -potenziert, -wasauchimmer-iert. Ich meine aber auch, dass von denen überladene Versionen existieren, bei denen man das Epsilon selbst übergeben kann. Im Grunde sehen die intern auch nicht viel anders aus als das händische abs(wert-vergleichswert)<epsilon, ist im Code nur hübscher leserlich.

marcibaer 27. Jan 2010 16:29

Re: Vergleich von Real-Werten ---> klappt nicht
 
Hallo zusammen!

Wenn es doch IMMER nur um max. 2 Nachkomma-Stellen geht, kann man doch das Ganze einfach mit 100 multiplizieren.
Die Konstanten wären dann also z.B. 102 , 576 oder 805 - und die Ungenauigkeiten sind weg!
So rechne ich immer, wenn ich mit Geld-Beträgen zu tun habe - also in Cent und nicht in Euro!

Hoffe, das macht es einfacher!?

Marcibaer

markus5766h 27. Jan 2010 16:47

Re: Vergleich von Real-Werten ---> klappt nicht
 
Zitat:

Zitat von marcibaer
Hallo zusammen!

Wenn es doch IMMER nur um max. 2 Nachkomma-Stellen geht, kann man doch das Ganze einfach mit 100 multiplizieren.
Die Konstanten wären dann also z.B. 102 , 576 oder 805 - und die Ungenauigkeiten sind weg!
So rechne ich immer, wenn ich mit Geld-Beträgen zu tun habe - also in Cent und nicht in Euro!

Hoffe, das macht es einfacher!?

Marcibaer

leider nicht ganz :
bei den Konstanten gebe ich Dir recht, diese könnten dann Integer-Werte werden.
Beim Ergebnis "Rv" nützt das allerdings nicht viel, wenn die Ungenauigkeit erst
an vierter, fünfter (oder weiß wo ..) Stelle nach dem Komma auftritt:
102 ist eben nicht gleich 102,0000000012

wie Daniel schon geschrieben hat, nützt da auch das Casten nach Integer nichts.

himitsu 27. Jan 2010 17:08

Re: Vergleich von Real-Werten ---> klappt nicht
 
Für Geldbeträge nimmt man Currency, denn dieses rechnet auf 4-Nachkommastellen genau
und ist intern ein skalierter Int64.


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:19 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