Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi if-Abfrage mit Extended - Trotz gleichheit False (https://www.delphipraxis.net/171459-if-abfrage-mit-extended-trotz-gleichheit-false.html)

Captnemo 7. Nov 2012 13:24

if-Abfrage mit Extended - Trotz gleichheit False
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hi,

mal wieder ein Phänomen, was ich mir so nicht erklären kann. Aber vielleicht könnt ihr mir auf die Sprünge helfen.

Ich habe eine Function, die verschiedene Werte auf gleichheit Prüfen soll.
Doch leider scheint das bei Datentyp Extended nicht zu klappen, obwohl laut Debugger der Wert gleich ist.

Ich habe mal einen Screenshot beigefügt, dann wird deutlich was ich meine. Der Code ist schrecklich, ich weiß. Ist nur für's debugging so geschrieben.

flipdascript 7. Nov 2012 13:29

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
Der für die Anzeige aufbereitete Wert ist gleich. Der in den Variablen stehende Wert ist es nicht.
Für Vergleiche von Fließkommazahlen solltest Du CompareeValue aus der Math-Unit verwenden.

sahimba 7. Nov 2012 13:32

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
Hi,

Die Fließkommazahlen sind aufgrund ihrer internen Darstellung nicht exakt gleich (irgendwo an der gefühlt 190.000 Nachkomastelle), auch wenn der Debugger dies so anzeigen mag. Verwende die Funktion CompareValue, welche hier eine (minimale) Toleranz berücksichtigt.
Siehe: http://www.delphibasics.co.uk/RTL.asp?Name=CompareValue

Cheers,
S.

stahli 7. Nov 2012 13:43

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
Folgendes hatte ich mal zu dem Thema zusammen gesucht:


http://de.wikipedia.org/wiki/Rundungsfehler
http://de.wikipedia.org/wiki/Gleitkommazahl

Zitat:

Prüfung auf Gleichheit
Die im Abschnitt Dezimalzahlen genannte Einschränkung, dass viele Dezimalzahlen in Binärsystemen in Computern nicht exakt dargestellt werden können, hat beim Programmieren Auswirkungen auf Vergleiche zwischen Fließkommazahlen. Ein Beispiel in C soll dies verdeutlichen:
#include "stdio.h"
int main(){
if(.362*100. != 36.2)
printf("verschieden\n");

if(.362*100./100. != .362)
printf("auch verschieden\n");
return 0;
}
Obwohl die beiden Gleichungen und mathematisch korrekt sind, werden sie wegen der ungenauen Umrechnung ins Computer-Binärsystem falsch. Im Beispiel-Programm werden somit beide Ungleichungen als wahr angesehen.
Vergleiche müssen deshalb durch eine Abfrage ersetzt werden, ob die zu vergleichenden Werte im Rahmen einer erreichbaren Genauigkeit (meist Toleranz genannt) als gleich angesehen werden können.
Toleriert man beim Vergleich einen absoluten Fehler, lautet eine mögliche Formulierung .
Toleriert man beim Vergleich einen relativen Fehler, lautet eine mögliche Formulierung . Der zweite Fall muss meist noch mit der Sonderfallabfrage verbunden werden.
Sogar Zahlen mit exakt denselben Bitmustern und somit eigentlich exakt identischen Werten werden vom Rechner mit manchmal nicht als gleich angesehen. Das hat als Ursache die manchmal nicht identischen Formate im Speicher (Bsp.: Intel 64 Bit) und während einer Rechnung in der Gleitpunkteinheit (Bsp.: Intel 80 Bit). Wenn dieselben Bitmuster, die verglichen werden sollen, einmal aus dem Speicher und somit gerundet und einmal aus der FPU und somit mit der vollen Genauigkeit kommen, führt ein Vergleich zum falschen Ergebnis. Die Abhilfe ist dieselbe wie schon beschrieben.

Captnemo 7. Nov 2012 13:52

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
Jepp, das wars ;-) Super, vielen Dank. Hätt ich jetzt gar nicht gedacht.

Da der eine Wert aus einer MSSQL-DB stamt, der zweite jedoch aus einer Textdatei umgesetzt wird, wärs jetzt mal interessant, wer mir den Unterschied an x-ten Stelle da reinschummelt....ich fürchte mal des SQL-Server.

Medium 7. Nov 2012 15:34

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
Da schummelt keiner etwas rein - bzw. könnten sogar schon die Programme dafür "verantwortlich" sein, die diese Werte geschrieben haben. In Gänsefüßchen, weil letztlich immer nur die FPU, bzw. eigentlich die Bitbreite der FPU das wichtige ist. Die Ungenauigkeit ist im grundlegensten Prinzip der Fließkommarechnung begründet, und tritt immer und überall auf, wo Fließkommazahlen verwendet werden. Und jede einzelne Operation macht es schlimmer, so dass man (fast) sagen kann: Je mehr Rechenschritte eine Zahl durchlaufen musste, desto größer ist der Fehler im Vergleich zu einer hypothetischen Unendlich-Bit-FPU. Kommt noch Um- und Rückwandlung mit Strings dazu, wird es feierlich :). Da gibt's keinen Schuldigen*, das ist einfach so.

*) Man kann komplexe Rechnungen z.T. geschickt genug aufbauen um die Aufsummierung der Fehler zu minimieren, aber gemacht wird er eigentlich immer.

PS: Das ist eigentlich etwas, was jedem Entwickler/Informatiker am ersten Tag von Ausbildung/Studium beigebracht werden müsste. Und dann täglich wiederholt, wenn man zugrunde legt, wie oft die Frage hier auftaucht =)

Puke 7. Nov 2012 15:41

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
Und wofür braucht man ultragenaue Rechnungen, die dann sowieso falsch sind?:shock:
Bisher runde ich auch Float-Zahlen zu Integer, die sind sowieso die einfachsten! :-D

p80286 7. Nov 2012 16:36

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
Hast Du schon mal etwas von Logarithmen gehört?
oder Rechenschieber?
Fließkommazahlen arbeiten nach dem gleichen Prinzip, so genau wie nötig.
Wenn Du es ganz genau haben willst dann mußt Du eben Currency oder ähnlich Typen nutzen.

Gruß
K-H

Puke 7. Nov 2012 16:38

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
wie genau muss es denn sein?
Wenn die 5. Zahl noch bedeutend ist. Tschuldigung
allerdings kann man sonst runden oder den Wert mal 1000 nehmen und in ein Integer runden.

Sir Rufo 7. Nov 2012 18:56

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
Zitat:

Zitat von Puke (Beitrag 1190185)
wie genau muss es denn sein?
Wenn die 5. Zahl noch bedeutend ist. Tschuldigung
allerdings kann man sonst runden oder den Wert mal 1000 nehmen und in ein Integer runden.

Currency ist intern ein Int64 wo die letzten 4 Stellen als Nachkommastellen verwendet werden ;)

himitsu 7. Nov 2012 19:00

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
Delphi-Referenz durchsuchenCompareValue wurde doch schon genannt.
Da gibt es einen zweiten Parameter, wo man die maximal erlaubte Differenz einstellen kann.
Und nun rate man, was man dort angeben muß, wenn man 5 Nachkommastellen vergleichen will.

'ne Zahl mit mindestens 5 Nullen nach dem Komma. :roll:

Captnemo 7. Nov 2012 21:04

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
Das mit CompareValue habe ich auch verwendet, und das liefert mir jetzt genau, dass was ich haben wollte.
Letztlich hätte ich auch

if (Trunc(wert1*100)=Trunc(wert2*100)) then ...

machen können, wäre auf's gleich rausgekommen. (Welche Veriante jetzt mehr Rechenzeit beansprucht sei mal dahingestellt).

In meinem Fall ist es so, dass keiner der beiden zu vergleichenden Werten berechnet ist.

Der erste Wert wurde aus einer Textdatei gelesen und in Extended umgewandelt, also explizit mit 2 Nachkommastellen zugeweisen. Dann eine einem Float-Feld einer DB gespeichert.
Danach wird er wieder gelesen.
Der zweite Wert wird auch aus der gleichen Textdatei gelesen, und mit dem aus der DB zurückgelesenen verglichen.

Also wurde, nach meinem Empfinden keiner der beiden Werte "berechnet" bzw. mittels Rechneroperationen bearbeitet. Es sei denn der Transport durch die ADO-Komponenten beinhaltet irgendwelche Rechenoperationen, dass weiß ich natürlich nicht.

Also stellt sich mir die Frage, ob eine Zuweisung ala

Delphi-Quellcode:
var
  wert: Extended;
  s: String;
begin
  s:='-29.90';
  wert:=StrToFloat(s)
auch evtl. abweichende Nachkommastellen hinterläßt.

Sir Rufo 7. Nov 2012 21:40

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
Entschuldige, aber diese Fragestellung ist doch wohl Unfug.

Das Problem kommt doch von einer anderen Stelle. Du hast 2 Systeme im Einsatz von wo du die Daten bekommst.

Um dieses Phänomen wirklich zu untersuchen, solltest du Die Zahl von String in ein Extended und dann in die Datenbank schreiben. Dann aus der Datenbank wieder auslesen und mit dem Wert wieder vergleichen.

Auch wenn es hier jetzt zu einer Gleichheit kommt, kannst du dich aber niemals darauf verlassen, weil du nicht wissen kannst, wie der Wert in die Datenbank gekommen ist (direkte Zuweisung oder durch eine Berechnung oder woher auch immer).

Zudem sollte dieses Problem bei Fließkommazahlen bekannt sein. Und wenn man mal genau darüber nachdenkt, dann kommt man auch darauf, dass man ja nur endlich Informationen zu einem Wert speichern kann, es aber ganz prominent die Zahl PI gibt, die aus einer unendlichen Folge von Nachkommastellen besteht. Wie soll man also etwas unendliches in einem endlichen System speichern können ohne eben so eine Annäherung zu benutzen? Es kommt eben auf die Genauigkeit an, die ich benötige und diese bestimmt, welche Ungenauigkeit ich verkraften kann.

jfheins 7. Nov 2012 21:43

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
Zitat:

Zitat von Captnemo (Beitrag 1190227)
Also stellt sich mir die Frage, ob eine Zuweisung ala
...
auch evtl. abweichende Nachkommastellen hinterläßt.

Ganz klar ja. Denn die 0.9 lassen sich nicht exakt als Zweierpotenz schreiben.
Der Computer macht daraus bei der Umwandlung sowas wie
Code:
29.9  = 11101.111001100110011
Und das ergibt jetzt 0.9001464844 im Dezimalsystem. Mit mehr Stellen wird es noch genauer, aber es deutet sich bereits an dass der Nachkommaanteil periodisch ist und somit durch eine endliche Anzahl an Bits nur angenähert werden kann ;-)

Furtbichler 8. Nov 2012 06:43

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
Vielleicht noch eine Anmerkung zu dem Thema: Früher wurde in Computersystemen anstatt mit Floating Point mit BCD-Arithmetik gerechnet. Dabei wird jede Ziffer durch 4 Bits dargestellt. Das führt dazu, das man 0.9 exakt so darstellen kann, und PI eben nicht. Irgendwie einfach zu verstehen, das Ganze: Genau aufschreibbar = Genau gespeichert.

Das ist bei Floating Point nicht der Fall, aber dafür kann man mit FP viel viel schneller rechnen. Ich persönlich habe ca. 10 Jahre meiner Programmiertätigkeit ausschließlich mit BCD gearbeitet und empfinde daher die unnatürliche Problematik "1.1 <> 1.1" als dem 21. Jahrhundert nicht würdig. Mit BCD wäre man in der Lage, viel genauer zu rechnen, da es die Rundungsfehler durch falsche interne Darstellung nicht gibt. Natürlich gibt es Rundungsfehler durch Rechnerei, aber das ist ein anderes Thema.

Aber letztendlich ist diese Problematik so mit der einzige Nachteil von FP ggü BCD mit vergleichbarer Genauigkeit, soweit ich informiert bin.

Medium 8. Nov 2012 08:12

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
Die Vorteile von Floats der direkten Vergleichbarkeit zu opfern wäre glaube ich auch nicht der goldene Weg. Was Floats gerade so nett macht ist, dass man einen irren Wertebereich damit abdecken kann, da es nur eine Anzahl signifikanter Stellen gibt - es ist aber egal wo dabei das Komma sitzt. Dass dabei dann non-uniforme Lücken zwischen den einzelnen Werten entstehen, deren Werte man folglich auch nicht genau darstellen kann, ist eine Notwendigkeit dabei. Sowas muss ich als Informatiker einfach lernen, der Maurer weiss ja auch um die richtigen Einsatzgebiete von Gummihammer und Kelle.

Am Rande: Ich empfinde BCD irgendwie als "unnatürlich" und "bloaty", weil eben Dezimalziffern in 4 Bit dargestellt werden. Da bleiben Kapazitäten ungenutzt, und Binärrechner zu zwingen in Hardware dezimal zu rechnen... würg :) Und letztlich ist der Genauigkeitsgewinn nur dort vorhanden, wo vornehmlich von Menschen eingegebene Zahlen eine Rolle spielen. Und schlussendlich ist es auch nur ein seltsam kodiertes Festkommaformat; da doch lieber gleich Currency.

Blup 8. Nov 2012 08:32

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
Für Werte die ohne Rundungsdifferenzen gespeichert werden müssen, kann das Feld in der Datenbank als "Numeric(a,b)" (a Anzahl Vorkommastellen, b Anzahl Nachkommastellen) deklariert werden. Problemtisch ist eventuell das Auslesen, da die verwendeten Komponenten in der Regel in ein Fließkommaformat konvertieren.

Bummi 8. Nov 2012 08:42

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
@Blup
schön wäre es, Ado interpretiert es als TFMTBCD oder TBCD und ein cxGrid explodiert damit, also muss hier der Feldtyp manuell ausgetauscht werden. (sorry füt OT)

DanielJ 8. Nov 2012 09:21

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
Hallo,


2 Anmerkungen:
1. für einfache vergleiche SameValue verwenden, gibt dann auch eine Bool zurück wie in
Code:
//if x=y then DoSth;
//stattdessen
if SameValue(x,y) then DoSth;
CompareValue ist etwas unhandlicher (und verwendet intern selber SameValue) wenn einen nicht interresiert ob ungleich-kleiner oder ungleich-größer.

2. Kleiner Artikel zur Problematik: What Every Computer Scientist Should Know About
Floating-Point Arithmetic


LG,
Daniel

Captnemo 8. Nov 2012 10:32

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
Zitat:

Zitat von Sir Rufo (Beitrag 1190233)
Entschuldige, aber diese Fragestellung ist doch wohl Unfug.

Warum so unfreundlich? Was ist Unfug daran, einen Frage zu etwas zu stellen um sich eine Problematik zu verdeutlichen?

Zitat:

Zitat von Sir Rufo (Beitrag 1190233)
Um dieses Phänomen wirklich zu untersuchen, solltest du Die Zahl von String in ein Extended und dann in die Datenbank schreiben. Dann aus der Datenbank wieder auslesen und mit dem Wert wieder vergleichen.

Genauso mache ich es ja, dadurch bin ich ja überhaupt auf die Frage gestoßen.

Zitat:

Zitat von jfheins (Beitrag 1190235)
Zitat:

Zitat von Captnemo (Beitrag 1190227)
Also stellt sich mir die Frage, ob eine Zuweisung ala
...
auch evtl. abweichende Nachkommastellen hinterläßt.

Ganz klar ja. Denn die 0.9 lassen sich nicht exakt als Zweierpotenz schreiben.
Der Computer macht daraus bei der Umwandlung sowas wie
Code:
29.9  = 11101.111001100110011
Und das ergibt jetzt 0.9001464844 im Dezimalsystem. Mit mehr Stellen wird es noch genauer, aber es deutet sich bereits an dass der Nachkommaanteil periodisch ist und somit durch eine endliche Anzahl an Bits nur angenähert werden kann ;-)

Das leuchtet mir natürlich ein.

Sir Rufo 8. Nov 2012 11:00

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
Zitat:

Zitat von Captnemo (Beitrag 1190297)
Zitat:

Zitat von Sir Rufo (Beitrag 1190233)
Entschuldige, aber diese Fragestellung ist doch wohl Unfug.

Warum so unfreundlich? Was ist Unfug daran, einen Frage zu etwas zu stellen um sich eine Problematik zu verdeutlichen?

Zitat:

Zitat von Sir Rufo (Beitrag 1190233)
Um dieses Phänomen wirklich zu untersuchen, solltest du Die Zahl von String in ein Extended und dann in die Datenbank schreiben. Dann aus der Datenbank wieder auslesen und mit dem Wert wieder vergleichen.

Genauso mache ich es ja, dadurch bin ich ja überhaupt auf die Frage gestoßen.

Also deine Frage war:
Zitat:

Zitat von Captnemo (Beitrag 1190227)
Also stellt sich mir die Frage, ob eine Zuweisung ala

Delphi-Quellcode:
var
  wert: Extended;
  s: String;
begin
  s:='-29.90';
  wert:=StrToFloat(s)
auch evtl. abweichende Nachkommastellen hinterläßt.

Und genau das meinte ich mit Unfug, denn das gleiche System wird bei dieser Anweisung auch immer das gleiche Ergebnis liefern. Du hast aber 2 Systeme im Spiel und darum kannst du mit diesem Ansatz das nicht ergründen.

p80286 8. Nov 2012 11:41

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
Zitat:

Zitat von Medium (Beitrag 1190277)
Am Rande: Ich empfinde BCD irgendwie als "unnatürlich" und "bloaty", weil eben Dezimalziffern in 4 Bit dargestellt werden. Da bleiben Kapazitäten ungenutzt, und Binärrechner zu zwingen in Hardware dezimal zu rechnen... würg :) Und letztlich ist der Genauigkeitsgewinn nur dort vorhanden, wo vornehmlich von Menschen eingegebene Zahlen eine Rolle spielen. Und schlussendlich ist es auch nur ein seltsam kodiertes Festkommaformat; da doch lieber gleich Currency.

BCD ist kein Festkommaformat, sondern eine nicht binäre Kodierung. Mann kann natürlich eine entsprechende Vereinbarung treffen ist aber wesentlich flexibler als Currency.

Und was die Menschen angeht, versuch einmal einem Mitarbeiter zu erklären warum auf seiner Gehaltsabrechnung immer wieder Rundungsfehler auftauchen, bei Werten, die jeder mäßig begabte Grundschüler addieren kann. Nichts gegen Floatingpoints, aber sie sind nun mal nicht für alles die richtige Lösung.

Gruß
K-H

Medium 8. Nov 2012 14:01

AW: if-Abfrage mit Extended - Trotz gleichheit False
 
Deswegen ja Currency (oder ein anderes Fixed-Format mit der gewünschten Nachkommaanzahl, da ist man ja genau so frei wie mit BCD). Und naja, BCD ist an sich ein Integerformat, daher meinte ich Festkomma - man kann es nur als Fixed für Zahlen mit Nachkommaanteil benutzen. Wo genau da jetzt der Vorteil gegenüber der binären Integerdarstellung sein soll erschließt sich mir noch immer nicht.


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