.
Anmeldung | Registrieren | Hilfe |
Suchen
Home Foren News Member Offers Termine Developer Blogs Knowledge Base

Navigation

Skip Navigation Links.
Collapse Knowledge BaseKnowledge Base
Collapse TutorialsTutorials
Webentwicklung
Cliententwicklung
Datenbankentwicklung
IT Professional
Sharepoint
Collapse SprachspezifischSprachspezifisch
C#
Visual Basic
C++
XAML
SQL
JavaScript
Collapse ErfahrungsberichteErfahrungsberichte
Entwicklersoftware
Bücher
FAQ Grundlagen

Verknüpfungen

  • Knowledge Base durchsuchen
  • Hilfe zur Knowledge Base
  • RSS Feed
  • Twitter

Vergleich von Gleitkommazahlen

Ich merke immer wieder dass vielen das Verständnis von Gleitkommazahlen fehlt und deshalb oft eine Vergleich mit == durchgeführt wird. Dies ist aber nicht korrekt.

Beispiel:

double d1 = 3.3;
double d2 = 1.1 + 2.2;
if (d1 == d2)
Console.WriteLine("gleich");
else
Console.WriteLine("ungleich");

Beim Ausführen des Code wird die korrekte Ausgabe “gleich” erwartet, es erscheint jedoch “ungleich”. Wie ist das möglich? Ist meine CPU defekt?

Die Begründung in diesem Verhalten liegt darin dass Gleitkommazahlen (float, double) im Rechner nur als Näherung einer reellen Zahl dargestellt werden. Es treten also Rundungsfehler auf. In der Numerik gibt es ganze Kapitel über die Behandlung von Fehlern und der Fortpflanzung. So weit gehe ich hier aber nicht.

Durchläuft man obigen Code mit dem Debugger und schaut sich die Werte von d1 und d2 an so kann festgehalten werden:

d1    3.3    double
d2    3.3000000000000003    double

Also existiert nur ein kleiner Unterschied in beiden Werten, der Vergleich mit == liefert somit korrekt das falsche Ergebnis.

Wie werden Gleitkommazahlen verglichen?

Es liegt somit Nahe einen Vergleich mit einer Toleranz durchzuführen. Dieses Toleranz wird in der Numerik üblicherweise als Epsilon bezeichnet.

Somit muss obiger Code geändert werden zu:

if (Math.Abs(d1 - d2) < epsilon)
Console.WriteLine("gleich");
else
Console.WriteLine("ungleich");

Wie groß soll Epsilon gewählt werden?

Die Datentypen System.Single (float) und System.Double (double) bietet eine Konstante namens Epsilon an. Diese entspricht aber nicht der Definition von Epsilon im Sinne der Numerik. Dieses Epsilon stellt die kleinste positive von 0 verschiedene Zahl dar.

Epsilon im Sinne der Numerik wird wie folgt berechnet:

public static double Epsilon()
{
double tau = 1.0;
double walt = 1.0;
double wneu = 0.0;

while (wneu != walt)
{
tau *= 0.5;
wneu = walt + tau;
}

return 2.0 * tau;
}

Es wird die Schleife so lange durchgeführt bis zwei Gleitkommazahlen als gleich erachtet werden. Dieses Epsilon (kann natürlich auch für float errechnet werden) sollte für Vergleiche von Gleitkommazahlen verwendet werden.

Epsilon für float: 1,192093E-07
Epsilon für double: 2,22044604925031E-16

von gfoidl, 03.08.2009 zugeordnet zu FAQ Grundlagen .

Kommentare

Ergänzende Inforamtion über den Vergleich von Gleitkommazahlen finden sich unter http://dotnet-forum.de/forums/p/1755/6294.aspx#6294
von gfoidl, 16.08.2009.

Eigener Kommentar

Sie müssen angemeldet sein, um ein Kommentar zu erstellen.
  • Schwierigkeit: Einsteiger
  • Views: 1279
  • Zur Druckversion
  • Artikel von gfoidl

Kick it on dotnet-kicks.de

Artikel

Autor

Kick it!

Wenn ihnen dieser Artikel gefällt, bitte "kicken" sie ihn.
Das Team | Regeln | Impressum