www.mikrocontroller.net

Forum: Compiler & IDEs Floats vergleichen


Autor: Hr Vorragend (hr_vorragend)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Εrnst B✶ (ernst)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 + ...

Autor: muh (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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;
}

Autor: A.K. (Gast)
Datum:

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

Autor: Hr Vorragend (hr_vorragend)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke!

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Εrnst B✶ (ernst)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Ingo Elsen (ogni42)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.