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