DigitList bug in recent patch

Olivier Lagneau olivier.lagneau at oracle.com
Wed Mar 27 16:32:23 UTC 2013


Hi Franck,

Below is a variation of your program that shows the closest bynary 
representation of the v value you provide:

--------------------------
import java.math.RoundingMode;
import java.math.BigDecimal;

public class FrankDing {

     public static void main(String[] args) {

         java.text.NumberFormat numberFormat = 
java.text.NumberFormat.getInstance(
                 java.util.Locale.US);
         double v = 78.00005;

         // Prints-out first the "approximated" double floating-point value
         System.out.println("FloatingDecimal output : " + v);
         // Then the exact binary representation using as much memory as 
needed
         System.out.println("BigDecimal      output : " + new 
BigDecimal(v).toString());

         numberFormat.setMaximumFractionDigits(4);
         numberFormat.setRoundingMode(RoundingMode.HALF_EVEN);
         numberFormat.setMinimumFractionDigits(0);
         numberFormat.setGroupingUsed(false);
         String ret = numberFormat.format(v);
         System.out.println(ret);
     }
}
--------------------------

Best Regards,
Olivier.

Olivier Lagneau said  on date 3/27/2013 5:09 PM:
> 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