DigitList bug in recent patch (original) (raw)
Olivier Lagneau olivier.lagneau at oracle.com
Wed Mar 27 16:09:44 UTC 2013
- Previous message: DigitList bug in recent patch
- Next message: DigitList bug in recent patch
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Hi Frank,
We discovered some time ago a long-standing bug in the DigitList.java class (see bug 7131459 <http://bugs.sun.com/view_bug.do?bug_id=7131459>). we have fixed it and this is now in the latest JDK8 builds
The fact is that decimal value 78.00005 cannot be represented exactly in a binary representation. The closest binary representation to 78.00005 is 78.0000500000000016598278307355940341949462890625 As you can read this "above" the tie value "78.00005".
So the closest binary representation of 78.00005 that can be recorded in a computer is a bit greater than the "tie" value provided in the program text ("78.00005"), and for this reason, as stated below in new DiigitList code : " // value was above tie and FloatingDecimal truncated // digits to tie. We must round up. " We must round up the result to provide an exact and fair HALF-EVEN rounding of what is recorded in the computer, since this value is "above" the tie.
Thus the correct result to return here is 78.0001 because maximumFractionDigits is set to 4, and exact rounding changes the '0' digit in 4th fractional position to a '1'.
If you choose for example v=78.10005, which closest binary representation is 78.1000499999999959754859446547925472259521484375, the returned result would be 78.1 since the binary representation is "below" the tie.
The previous behavior of JDK (DigitList) was wrong because it did no took correctly into account what value is recorded in memory, and the new behavior is the correct one.
Hope that helps, Olivier.
Frank Ding said on date 3/27/2013 8:48 AM:
Hi guys, We noticed there is a recent change (patch @ http://hg.openjdk.java.net/jdk8/jdk8/jdk/rev/bc1f16f5566f ) that changed the behavior of the following program.
import java.math.RoundingMode; public class TestNumberFormat { public static void main(String[] args) { java.text.NumberFormat numberFormat = java.text.NumberFormat.getInstance( java.util.Locale.US); double v = 78.00005; numberFormat.setMaximumFractionDigits(4); numberFormat.setRoundingMode(RoundingMode.HALFEVEN); numberFormat.setMinimumFractionDigits(0); numberFormat.setGroupingUsed(false); String ret = numberFormat.format(v); System.out.println(ret); } } Note the rounding mode HALFEVEN and the expected output should be "78" which can also be verified by running previous jdk (before b73). Stepping into code and the suspicious code is in DigitList.shouldRoundUp(). allDecimalDigits is false so true is returned, causing the last digit in fraction part to be 1. case HALFEVEN: // Implement IEEE half-even rounding if (digits[maximumDigits] > '5') { return true; } else if (digits[maximumDigits] == '5' ) { if (maximumDigits == (count - 1)) { // the rounding position is exactly the last index : if (alreadyRounded) // If FloatingDecimal rounded up (value was below tie), // then we should not round up again. return false; if (!allDecimalDigits) // Otherwise if the digits dont represent exact value, // value was above tie and FloatingDecimal truncated // digits to tie. We must round up. return true; Since I am not familiar of the numeric conversion, can any one shed your light on it? Best regards, Frank
- Previous message: DigitList bug in recent patch
- Next message: DigitList bug in recent patch
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]