DigitList bug in recent patch

Olivier Lagneau olivier.lagneau at oracle.com
Wed Mar 27 16:09:44 UTC 2013


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.HALF_EVEN);
>         numberFormat.setMinimumFractionDigits(0);
>         numberFormat.setGroupingUsed(false);
>         String ret = numberFormat.format(v);
>         System.out.println(ret);
>     }
> }
>
> Note the rounding mode HALF_EVEN 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 HALF_EVEN:
>                 // 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
>




More information about the core-libs-dev mailing list