RoundingMode.HALF_DOWN Problem in Java8

8

Ich benutze jdk 1.8.0_45 und unsere Tests haben einen Fehler im Rouding entdeckt. RoundingMode.HALF_DOWN funktioniert genauso wie RoundingMode.HALF_UP, wenn die letzte Dezimalzahl, die die Rundung entscheidet, 5 ist.

Ich habe verwandte Probleme mit RoundingMode.HALF_UP gefunden, aber sie sind in Update 40 behoben. Ich habe dem Orakel auch einen Fehler hinzugefügt, aber meiner Erfahrung nach reagieren sie wirklich nicht.

%Vor%

Tatsächliches Ergebnis: Abrunden 10.5556 Zusammenfassen 10.5556

Erwartetes Ergebnis (mit jdk 1.7 erhalten): Abrunden 10.5555 Zusammenfassen 10.5556

    
cristi 11.06.2015, 10:59
quelle

2 Antworten

10

Scheint, dass es geändert werden soll. Das JDK 1.7-Verhalten war falsch.

Das Problem ist, dass Sie einfach nicht die Zahl 10.55555 mit dem double -Typ darstellen können. Es speichert die Daten im IEEE-Binärformat. Wenn Sie also der 10.55555 -Variable die dezimal double -Nummer zuweisen, erhalten Sie tatsächlich den nächsten Wert, der im IEEE-Format dargestellt werden kann: 10.555550000000000210320649784989655017852783203125 . Diese Zahl ist größer als 10.55555 , daher ist sie richtig auf 10.5556 in HALF_DOWN mode gerundet.

Sie können einige Zahlen überprüfen, die im Binärformat genau dargestellt werden können. Zum Beispiel 10.15625 (das ist 10 + 5/32 , also 1010.00101 in binär). Diese Zahl wird auf 10.1562 in HALF_DOWN mode und 10.1563 in HALF_UP mode aufgerundet.

Wenn Sie das alte Verhalten wiederherstellen möchten, können Sie Ihre Nummer zuerst in BigDecimal konvertieren, indem Sie BigDecimal.valueOf Konstruktor, der ein double in ein BigDecimal übersetzt, indem er die kanonische Zeichenkette" double "verwendet:

%Vor%     
Tagir Valeev 11.06.2015, 11:50
quelle
5

Die Änderung des Verhaltens ist in den Versionshinweisen von Java 8

  

Bei Verwendung der Klassen NumberFormat und DecimalFormat war das Rundungsverhalten früherer JDK-Versionen in einigen Fällen falsch. [...]

     

Wenn Sie beispielsweise das standardmäßig empfohlene NumberFormatFormat API-Formular verwenden: NumberFormat nf = java.text.NumberFormat.getInstance() gefolgt von nf.format(0.8055d) , wird der Wert 0.8055d im Computer als 0.80549999999999999378275106209912337362766265869140625 aufgezeichnet, da dieser Wert nicht genau im Binärformat dargestellt werden kann. Hier ist die Standard-Rundungsregel "halb-gerade", und das Ergebnis des Aufrufs von format () in JDK 7 ist eine falsche Ausgabe von "0.806", während das korrekte Ergebnis "0.805" ist, da der Wert von Computer ist "unter" der Krawatte.

     

Dieses neue Verhalten wird auch für alle Rundungspositionen implementiert, die durch ein vom Programmierer gewähltes Muster definiert werden können (keine Standardmuster).

    
assylias 11.06.2015 12:17
quelle