Die Manipulation und Vergleich von floating-points in java
In Java der Gleitkomma-Arithmetik ist nicht vertreten, genau. Zum Beispiel dieser java-code:
float a = 1.2;
float b= 3.0;
float c = a * b;
if(c == 3.6){
System.out.println("c is 3.6");
}
else {
System.out.println("c is not 3.6");
}
Drucke "c ist nicht 3.6".
Ich bin nicht daran interessiert, Präzision jenseits von 3 Dezimalstellen (#.###). Wie kann ich den Umgang mit diesem problem zu vermehren schwimmt und vergleichen Sie zuverlässig?
- Deklarieren Sie Schwimmer wie:
float a = 1.2f;
- und Doppelzimmer wiedouble d = 1.2d;
Auch in if-Anweisung:if(c == 3.6f)
- Als Ergänzung zu @bobah 's Antwort, dem empfehle ich einen Blick auf die
Math.ulp()
Funktion.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Es ist eine Allgemeine Regel, dass die floating-point-Zahl sollten nie verglichen werden, wie (a==b), sondern eher wie
(Math.abs(a-b) < delta)
wo delta ist eine kleine Nummer.Eine floating-point-Wert mit festen Anzahl von Ziffern in dezimaler form nicht nötig haben Feste Anzahl von Ziffern in binärer form.
Zusätzlich für Klarheit:
Obwohl strenge
==
Vergleich von floating-point-zahlen hat sehr wenig praktischen Sinn, die strenge<
und>
Vergleich, im Gegenteil, ist es ein Gültiger Anwendungsfall (Beispiel - Logik-Triggerung, wenn bestimmten Wert überschreitet Schwelle:(val > threshold) && panic();
)<
mit>
erhalten Sie einen Kriterien für den Vergleich von floating-point-zahlen für die Ungleichheit in Bezug auf die Entfernung. Bitweise Identität von floating-point-zahlen, Darstellung in der computer-Speicher ist nicht von Interesse für die meisten praktischen Anwendungen==
ich weiß nicht (abgesehen vom CPU-Hersteller tests und dergleichen)Wenn Sie interessiert sind in fixed precision zahlen, sollten Sie mit einer festen Genauigkeit Typ wie
BigDecimal
, nicht inhärent Ungefähre (obwohl hohe Genauigkeit) type wiefloat
. Es gibt zahlreiche ähnliche Fragen auf Stack Overflow, die in diese im detail, in vielen Sprachen.Ich denke, es hat nichts zu tun mit Java, es kommt auf IEEE 754 floating-point-Zahl. Es ist wegen der der Art von floating-point-Darstellung. Alle Sprachen, die verwenden das IEEE-754-format wird die Begegnung mit dem gleichen problem.
Wie vorgeschlagen von David oben, verwenden Sie die Methode abs java.lang.Math-Klasse, um den absoluten Wert (Tropfen der positiv - /negativ-Vorzeichen).
Können Sie dies Lesen: http://en.wikipedia.org/wiki/IEEE_754_revision und auch eine gute numerische Methoden der text-Buch-Adresse das problem ausreichend.
Ich bin mit diesem Stück code in unit-tests zu vergleichen, wenn das Ergebnis von 2 verschiedenen Berechnungen sind die gleichen, abgesehen von floating point math Fehler.
Funktioniert es, indem man die Binär-Repräsentation der Gleitkomma-Zahl. Die meisten die Komplikationsrate ist aufgrund der Tatsache, dass das Zeichen von Gleitkomma-zahlen ist nicht zwei-Komplement. Nach dem Ausgleich, dass es im Grunde kommt es nur noch eine einfache Subtraktion, um die Differenz in ULPs (siehe den Kommentar unten).
Hier ist eine version für
double
precision floats:Float.floatToRawIntBits()
, die überprüfung für dieNaN
am Anfang der Methode. In der TatfloatToIntBits()
tut nichts, aber überprüfen Sie das Ergebnis fürNaN
ersetzt mit vordefinierten integer-Wert von0x7fc00000
. Der Hauptgrund für so etwas ist eine Tatsache, dassfloatToIntBits()
ruft tatsächlichfloatToRawIntBits()
, so dass es langsamer zu führen.Der andere Ansatz ist, überprüfen Sie die konvertierte bits für0x7fc00000
, aber Sie brauchen nicht beide Prüfungen.Dies ist eine Schwäche aller floating-point-Darstellungen, und es geschieht, weil einige zahlen, die scheinbar eine Feste Anzahl von Nachkommastellen im Zehnersystem, die eigentlich eine unendliche Anzahl von Dezimalzahlen in das Binär-system. Und so, was Sie denken, ist 1.2 ist tatsächlich so etwas wie 1.199999999997, weil bei der Darstellung in Binär-muss es abhacken der Dezimalstellen nach einer bestimmten Anzahl, und Sie verlieren etwas an Präzision. Dann Multiplikation mit 3 tatsächlich gibt 3.5999999...
http://docs.python.org/py3k/tutorial/floatingpoint.html <- könnte es besser erklären (auch wenn es für python, es ist ein gemeinsames problem der floating point Darstellung)
Wie die anderen schrieben:
Schreiben Sie eine schöne Methode dafür:
So, Sie können es verwenden, wie diese:
Es ist ein apache-Klasse für den Vergleich von doubles: org.apache.Unterhaus.math3.util.Präzision
Es enthält einige interessante Konstanten:
SAFE_MIN
undEPSILON
sind, die die maximal möglichen Abweichungen bei der Durchführung der arithmetischen Operationen.Es bietet auch die notwendigen Methoden zu vergleichen, die gleich oder Runde verdoppelt.
Vergleichen von zwei floats,
f1
undf2
innerhalb der Genauigkeit der#.###
ich glaube, Sie würden tun müssen, wie diese:f1 * 1000
Aufzüge3.14159265...
zu3141.59265
,+ 0.5
Ergebnisse in3142.09265
und die(int)
schneidet die Nachkommastellen,3142
. Das heißt, es beinhaltet 3 Nachkommastellen und rundet die Letzte Ziffer richtig.f1 == 3.1414999999999
undf2 == 3.1415000000001
.