Forum: Compiler & IDEs Floats vergleichen


von Hr V. (hr_vorragend)


Lesenswert?

Hallo

Hier ein Beispiel:

float f = 3,593;
float fa = 0;
char c;

for (c=0;c<10;c++)
  fa+=f;

fa/=10;

if (f==fa)
ist nie wahr - warum nicht?



Gruss

H:V

von Εrnst B. (ernst)


Lesenswert?

Weil floats eben auch auf Dualzahlen aufbauen, und deswegen (f/10)*10 
nicht gleich f sein muss. (Division durch 5 geht nicht auf...)

Manche Programmiersprachen (z.B. SML) bringen deswegen erst garkeinen 
Gleichheitsoperator für floats/double mit, um solche Fehler zu 
vermeiden.


Abhilfe:

if (fabs(f-fa) < 0.0000001) { ...

/Ernst

von A.K. (Gast)


Lesenswert?

Dezimale Zahlen mit Nachkommastellen sind oft nicht exakt im binären 
Fliesskommaformat darstellbar. Die Folge sind Rundungsfehler.

Versuch als Übung mal, die Zahl 0,1 als Summe von 1/(2**n) darzustellen, 
also 1/16 + 1/32 + ...

von muh (Gast)


Lesenswert?

geht net weil duch die binäre darstellung rechenfehler entstehen. dein 
taschenrechner lügt wenn er sagt 0,2+0,2+0,2+0,2+0,2-1,2 = 0.
hab jetzt kein weblink zu dem problem...
was du machen kannnst ist: if(abs(f-fa)<0.001 oder so.
nochwas: niemals floats als zähler verwenden.
float f;
int i;
for(f=0;f<=5;f+=0.1)
pfui!
lieber:
for(i=0;i<=50;i++) {
f=i/10;
}

von A.K. (Gast)


Lesenswert?

Ausgerechnet der Taschenrechner lügt nicht - denn der arbeitet 
wahrscheinlich dezimal. Hat's ja nicht eilig.

von Hr V. (hr_vorragend)


Lesenswert?

Danke!

von Peter D. (peda)


Lesenswert?

A.K. wrote:
> Ausgerechnet der Taschenrechner lügt nicht - denn der arbeitet
> wahrscheinlich dezimal. Hat's ja nicht eilig.

Nö, der rundet einfach nur 9-er Perioden.

Beim Keil Compiler gibts dafür floatfuzzy:

http://www.keil.com/support/docs/1415.htm


Peter

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ernst Bachmann wrote:

> Manche Programmiersprachen (z.B. SML) bringen deswegen erst garkeinen
> Gleichheitsoperator für floats/double mit, um solche Fehler zu
> vermeiden.

Bestimmte Gleichheits-Tests sind ja in C definiert, beispielsweise
lässt sich eine 0 immer exakt darstellen und damit auch vergleichen.

von Εrnst B. (ernst)


Lesenswert?

Jörg Wunsch wrote:

> Bestimmte Gleichheits-Tests sind ja in C definiert, beispielsweise
> lässt sich eine 0 immer exakt darstellen und damit auch vergleichen.

Klar, C stellt (wie die meisten anderen Sprachen) einfach einen 
Gleichheitsoperator für floats zur Verfügung, und baut darauf, dass dem 
Programmierer schon klar ist das der eine recht wacklige Sache ist.

SML kommt mehr aus der Mathematik/Theoretischen Informatik 
(lambda-Kalkül, etc), da haben die den weggelassen, weil er eben nicht 
"mathematisch korrekt" funktioniert.

Lustigerweise kann man auch unter SML das verhalten des C ==-Operators 
nachbauen, einfach mit Konstrukten wie !((a<b) || (b<a)) ;)

/Ernst

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ich wollte darauf hinaus, dass C für bestimmte Gleitkommazahlen
den Test auf Gleichheit garantiert, dafür ist er dann eben nicht
,,wackelig'' -- aber für alle anderen ist er es.

von Rolf Magnus (Gast)


Lesenswert?

Für bestimmte Zahlen schon. Allerdings garantiert C nicht, dass bei 
einer Berechnung auch wirklich diese bestimmten Zahlen rauskommen. Wenn 
ich 1/10*10-1 rechne, muss dabei nicht unbedingt 0 rauskommen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Rolf Magnus wrote:

> Wenn
> ich 1/10*10-1 rechne, muss dabei nicht unbedingt 0 rauskommen.

Das ist richtig.  Allerdings kann ich eine explizit (als Konstante)
zugewiesene oder initialisierte 0 als Vergleichswert benutzen,
bspw. um festzustellen, ob bereits ein anderer Wert eingetragen
worden ist.

Ohne Nachzugucken würde ich sagen, dass mindestens noch +Inf und
-Inf exakt vergleichbar sind.

von Ingo E. (ogni42)


Lesenswert?

Die Vergleiche sind natürlich in C immer richtig! Auch für 
float/double.

Die Schwierigkeit kommt, wie oben schon gesagt, durch die begrenzte 
Genauigkeit der Darstellung im Rechner. Es stehen eben nur eine 
begrenzte Anzahl bits zur Verfügung.

Somit macht C bei den Tests keine Fehler.

Bei Fließkommaberechnungen zwei Zahlen auf Gleichheit testen geht stets 
per:

fabs(a-b) < eps. eps ist dabei die betragsmäßig kleinste darstellbare 
Fließkommazahl.

eps ist definiert als FLT_EPSILON bzw. DBL_EPSILON in float.h

von Karl H. (kbuchegg)


Lesenswert?

> eps ist definiert als FLT_EPSILON bzw. DBL_EPSILON in float.h

Da musst du vorsichtig sein.
Diese XXX_EPSILON geben nur an, wieviel man zu eine
XXX 0 addieren muss, damit sich auch tatsächlich die
Bitdarstellung ändert. Es ist also die kleinste Zahl
die noch von 0 unterschieden werden kann.

Für Vergleiche, wie vorgeführt, ist das aber normalerweise
nicht geeignet. Wie gross dieses Epsilon sein muss, kann, darf
hängt unter anderem auch von der Vorgeschichte der Zahlen
ab. Also: woher kommen sie? welche Berechnungen mussten gemacht
werden um die zu vergleichenden Zahlen zu erhalten?
Danach richtet sich die Größe des zu verwendenden Epsilons.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.