JDK-8336279 : Incorrect data transformation in BigDecimal.valueOf(double) method
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.math
  • Affected Version: 17,19,21,23
  • Priority: P3
  • Status: New
  • Resolution: Unresolved
  • OS: generic
  • CPU: generic
  • Submitted: 2024-07-11
  • Updated: 2024-07-12
Description
ADDITIONAL SYSTEM INFORMATION :
Windows 11, Java 21.0.3-9

A DESCRIPTION OF THE PROBLEM :
Problem simulated in simple jUnit test - in which it is displayed that with the usage of "BigDecimal.valueOf(double)" incorrect object is created (most likely due to the new way of 'toString' method  in Double class)

@Test
    void testDoubleConversion() {
        final String stringRepresentation = "0212467111917324511";
        // after the conversion to double value is 2.12467111917324512E17 (this is OK)
        final double parsedDouble = Double.parseDouble(stringRepresentation);
        // after conversion to string - value is: 2.124671119173245E17 (last two digits are lost due to the new way of toString method in the Double class)
        final String backFromDouble = Double.toString(parsedDouble);
        // conversion back to double brings again the original value: 2.12467111917324512E17
        final double parsedFromBackFromDouble = Double.parseDouble(backFromDouble);
        assertEquals(parsedDouble, parsedFromBackFromDouble);

        // with the usage of constructor BigDecimal holds the same value as parsedDouble: 212467111917324512
        final BigDecimal bigDecimalFromDouble = new BigDecimal(parsedDouble);
        System.out.println(bigDecimalFromDouble);
        // with the usage of valueOf(double) precession is lost due to the new 'toString' method in the Double class: 2.12467111917324512E17
        final BigDecimal bigDecimalFromValueOf = BigDecimal.valueOf(parsedDouble);
        System.out.println(bigDecimalFromValueOf);
        // compare fail due to the fact that 'bigDecimalFromDouble' is greater number (due to the lost of last 2 digits in 'valueOf' conversion)
        assertThat(bigDecimalFromDouble, Matchers.comparesEqualTo(bigDecimalFromValueOf));
    }

REGRESSION : Last worked in version 17.0.11

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
jUnit which simulates the issue is added in Description

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Precession won't be lost during usage of "toString(double)" in BigDecimal class
ACTUAL -
Last two digits from the test are lost with the usage of toString(double) in BigDecimal class

---------- BEGIN SOURCE ----------

@Test
    void testDoubleConversion() {
        final String stringRepresentation = "0212467111917324511";
        // after the conversion to double value is 2.12467111917324512E17 (this is OK)
        final double parsedDouble = Double.parseDouble(stringRepresentation);
        // after conversion to string - value is: 2.124671119173245E17 (last two digits are lost due to the new way of toString method in the Double class)
        final String backFromDouble = Double.toString(parsedDouble);
        // conversion back to double brings again the original value: 2.12467111917324512E17
        final double parsedFromBackFromDouble = Double.parseDouble(backFromDouble);
        assertEquals(parsedDouble, parsedFromBackFromDouble);

        // with the usage of constructor BigDecimal holds the same value as parsedDouble: 212467111917324512
        final BigDecimal bigDecimalFromDouble = new BigDecimal(parsedDouble);
        System.out.println(bigDecimalFromDouble);
        // with the usage of valueOf(double) precession is lost due to the new 'toString' method in the Double class: 2.12467111917324512E17
        final BigDecimal bigDecimalFromValueOf = BigDecimal.valueOf(parsedDouble);
        System.out.println(bigDecimalFromValueOf);
        // compare fail due to the fact that 'bigDecimalFromDouble' is greater number (due to the lost of last 2 digits in 'valueOf' conversion)
        assertThat(bigDecimalFromDouble, Matchers.comparesEqualTo(bigDecimalFromValueOf));
    }
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
usage of "new BigDecimal(double)" instead of BigDecimal.valueOf(double) for Java 19 and above (most likely problem is caused by new implementation from https://bugs.openjdk.org/browse/JDK-4511638)

FREQUENCY : always



Comments
The observations on Windows 11: JDK 19ea+25: Passed. JDK 19ea+26: Failed, test for BigDecimal failed. JDK 21: Failed. JDK 23ea+14: Failed.
12-07-2024