Wie andere gesagt haben, ist dies nur ein grundsätzliches Problem, das Sie erhalten, wenn Gleitkommazahlen tun Arithmetik zu beliebig Basis. Es kommt einfach vor, dass Base-2 am häufigsten in Computern verwendet wird (weil es eine effiziente Hardware-Implementierung zulässt).
Die beste Lösung, wenn möglich, besteht darin, auf eine Art Quotientendarstellung der Zahl für Ihre Schleife umzuschalten, wodurch der Gleitkommawert daraus abgeleitet wird. OK, das klingt übertrieben! Für Ihren speziellen Fall würde ich es schreiben, wie:
int dTimes10 = 20;
double d;
while(dTimes10 != 0) {
dTimes10 -= 2;
d = dTimes10/10.0;
}
Hier sind wir wirklich mit Brüchen arbeiten [20/10, 18/10, 16/10, ..., 10.02, 0/10] wobei die Iteration mit Ganzzahlen (dh leicht zu korrigieren) im Zähler mit einem festen Nenner durchgeführt wird, bevor sie in Gleitkommawerte umgewandelt werden. Wenn Sie Ihre echte Iterationen umschreiben können, um so zu arbeiten, werden Sie großen Erfolg haben (und sie sind wirklich nicht viel teurer als das, was Sie vorher überhaupt taten, was ein großer Kompromiss ist, um Korrektheit zu erhalten).
Wenn Sie dies nicht tun können, müssen Sie equal-in-epsilon als Vergleich verwenden. Ungefähr, das ersetzt d != target
durch abs(d - target) < ε
, wo ε (epsilon) Auswahl manchmal peinlich sein kann. Grundsätzlich hängt der richtige Wert von ε von einer Reihe von Faktoren ab, aber es ist wahrscheinlich am besten als 0 ausgewählt.001 für die beispielhafte Iteration, gegeben durch die Skalierung des Schrittwerts (d. H. Es ist ein halbes Prozent der Größe des Schritts, so dass alles in diesem Fehler statt informativ sein wird).
Verwenden Sie niemals '==' mit Gleitkommawerten. Verwenden Sie vielleicht etwas wie "f> epsilon". – pascal
[Es war ein paar Tage, ich denke, wir waren überfällig.] (Http://docs.sun.com/source/806-3568/ncg_goldberg.html) – GManNickG
In Java, denke ich, gibt es die "Strictfp" Modifikator für solche Situationen –