In Java wird die Gleitkommaarithmetik nicht genau dargestellt. Zum Beispiel dieser Java-Code:
%Vor%Druckt "c ist nicht 3.6".
Ich bin nicht an einer Genauigkeit von mehr als 3 Dezimalstellen (#. ###) interessiert. Wie kann ich mit diesem Problem umgehen, um Floats zu multiplizieren und sie zuverlässig zu vergleichen?
Es ist eine allgemeine Regel, dass Gleitkommazahlen niemals wie (a == b) verglichen werden sollten, sondern eher wie (Math.abs(a-b) < delta)
, wobei delta em> eine kleine Zahl ist.
Ein Fließkommawert mit einer festen Anzahl von Ziffern in dezimaler Form muss nicht unbedingt eine feste Anzahl von Ziffern in binärer Form haben.
Zusatz für die Klarheit:
Obwohl der strikte ==
Vergleich von Fließkommazahlen sehr wenig praktischen Sinn hat, ist der strikte <
und >
Vergleich dagegen ein gültiger Use Case (Beispiel - Logic triggering wenn ein bestimmter Wert den Schwellenwert überschreitet: (val > threshold) && panic();
)
Wenn Sie an festen Präzisionszahlen interessiert sind, sollten Sie einen festen Genauigkeitstyp wie BigDecimal
verwenden, keinen inhärent ungefähren (wenn auch hochpräzisen) Typ wie float
. Es gibt zahlreiche ähnliche Fragen zu Stack Overflow, die in vielen Sprachen ausführlicher behandelt werden.
Ich denke, es hat nichts mit Java zu tun, es passiert auf jeder IEEE 754 Fließkommazahl. Dies liegt an der Natur der Gleitkommadarstellung. Alle Sprachen, die das IEEE 754-Format verwenden, stoßen auf das gleiche Problem.
Wie von David oben vorgeschlagen, sollten Sie die Methode abs der Klasse java.lang.Math verwenden, um den absoluten Wert zu erhalten (das positive / negative Vorzeichen löschen).
Sie können dies lesen: Ссылка und auch ein gutes Lehrbuch für numerische Methoden wird das Problem ausreichend lösen.
> %Vor%Dies ist eine Schwäche aller Fließkommadarstellungen, und dies geschieht, weil einige Zahlen, die im Dezimalsystem eine feste Anzahl von Dezimalzahlen zu haben scheinen, im Binärsystem tatsächlich eine unendliche Anzahl von Dezimalzahlen haben. Und was Sie denken ist 1.2 ist eigentlich etwas wie 1.1999999999997, denn wenn es in Binärdarstellung darstellt, muss es die Dezimalzahlen nach einer bestimmten Zahl abschneiden, und Sie verlieren etwas Präzision. Wenn man es dann mit 3 multipliziert, ergibt das 3.5999999 ...
Ссылка & lt; - dies könnte es besser erklären (auch wenn es für Python ist, ist es eine häufige Problem der Gleitkommadarstellung)
Wie die anderen geschrieben haben:
Vergleichen floats mit:
if (Math.abs(a - b) < delta)
Sie können eine schöne Methode dafür schreiben:
%Vor%So können Sie es wie folgt verwenden:
%Vor%Ich benutze dieses Codebeispiel in Komponententests, um zu vergleichen, ob das Ergebnis von zwei verschiedenen Berechnungen dasselbe ist, wenn Fließkomma-Rechenfehler ausgeschlossen werden.
Es funktioniert, indem man sich die binäre Darstellung der Fließkommazahl anschaut. Der größte Teil der Komplikation beruht auf der Tatsache, dass das Vorzeichen von Fließkommazahlen kein Zweierkomplement ist. Nach dem Ausgleich kommt es im Grunde nur auf eine einfache Subtraktion an, um den Unterschied in ULPs zu erhalten (erklärt in dem Kommentar unten).
%Vor% Hier ist eine Version für double
precision floats:
Es gibt eine Apache-Klasse zum Vergleichen von Doppelpunkten: org.apache.commons.math3.util.Precision
Es enthält einige interessante Konstanten: SAFE_MIN
und EPSILON
, die die maximal möglichen Abweichungen bei arithmetischen Operationen sind.
Es stellt auch die notwendigen Methoden zur Verfügung, um doppelte, gleiche oder runde zu vergleichen.
Um zwei Gleitkommazahlen zu vergleichen, f1
und f2
innerhalb der Genauigkeit von #.###
Ich glaube, Sie müssten das folgendermaßen machen:
f1 * 1000
lifts 3.14159265...
bis 3141.59265
, + 0.5
Ergebnisse in 3142.09265
und% (int)
löscht die Dezimalstellen, 3142
. Das heißt, es enthält 3 Dezimalstellen und rundet die letzte Ziffer richtig ab.
Tags und Links java floating-point floating-accuracy