-2

Double.toString(0.1) produces "0.1", but 0.1 is a floating point number.

Floating point number can't represent exactly in program language, but Double.toString produces the exact result (0.1), how does it do that, is it always produces the result that mathematically equal to the double literal?

Assume that the literal is in double precision.

Here is the problem I have see:

When use Apache POI to read excel file, XSSFCell.getNumericCellValue can only return double, if I use BigDecimal.valueOf to convert it to BigDecimal, is that always safe, and why?

ss.
  • 37
  • 5
  • 2
    `Double.toString(0.10)` will not produce `"0.10"` if that's really what you're asking. – khelwood Jul 12 '20 at 07:05
  • Did you mean how the string prints exact `0.1`, where in double number is not exact `0.1` – Eklavya Jul 12 '20 at 07:59
  • @Eklavya Yes. And is it always print exact result for literal input? – ss. Jul 12 '20 at 08:03
  • Double value in not represented exactly but the value in double is exact after assigning . That make sense ? – Eklavya Jul 12 '20 at 08:06
  • 1
    @Eklavya `double d = 0.1`. `d` doesn't exactly store the value. If use `new BigDecimal(0.1)` for test, print it, the result is `0.1000000000000000055511151231257827021181583404541015625`. – ss. Jul 12 '20 at 08:24

4 Answers4

3

Double.toString produces the exact result (0.1), how does it do that, is it always produces the result that mathematically equal to the double literal?

Double.toString(XXX) will always produce a numeral equal to XXX if XXX is a decimal numeral with 15 or fewer significant digits and it is within the range of the Double format.

There are two reasons for this:

  1. The Double format (IEEE-754 binary64) has enough precision so that 15-digit decimal numerals can always be distinguished.
  2. Double.toString does not display the exact Double value but instead produces the fewest significant digits needed to distinguish the number from nearby Double values.

For example, the literal 0.1 in source text is converted to the Double value 0.1000000000000000055511151231257827021181583404541015625. But Double.toString will not produce all those digits by default. The algorithm it uses produces “0.1” because that is enough to uniquely distinguish 0.1000000000000000055511151231257827021181583404541015625 from its two neighbors, which are 0.09999999999999999167332731531132594682276248931884765625 and 0.10000000000000001942890293094023945741355419158935546875. Both of those are farther from 0.1.

Thus, Double.toString(1.234), Double.toString(123.4e-2), and Double.toString(.0001234e4) will all produce “1.234”—a numeral whose value equals all of the original decimal numerals (before they are converted to Double), although it differs in form from some of them.

When use Apache POI to read excel file, XSSFCell.getNumericCellValue can only return double, if I use BigDecimal.valueOf to convert it to BigDecimal, is that always safe, and why?

If the cell value being retrieved is not representable as a Double, then XSSFCell.getNumericCellValue must change it. From memory, I think BigDecimal.valueOf will produce the exact value of the Double returned, but I cannot speak authoritatively to this. That is a separate question from how Double and Double.toString behave, so you might ask it as a separate question.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
2

10e-5d is a double literal equivalent to 10^-5
Double.toString(10e-5d) returns "1.0E-4"

Mark McElroy
  • 373
  • 4
  • 8
2

Well, double type has limited precision, so if you add enough digits after the floating point, some of them will be truncated/rounded.

For example:

System.out.println (Double.toString(0.123456789123456789))

prints

0.12345678912345678
Eran
  • 387,369
  • 54
  • 702
  • 768
  • Thank you for answer. Maybe my question is not clear. If digits are limited, in the double precision, and don't consider trailing 0. Does the result always mathematically equal to the literal? – ss. Jul 12 '20 at 07:36
  • @ss.your question says nothing about limiting the digits. Perhaps you should edit your question to make it precise. If you want to limit the digits, you have to specify your limit. – Eran Jul 12 '20 at 07:39
0

I agree with Eric Postpischil's answer, but another explanation may help.

For each double number there is a range of real numbers that round to it under round-half-even rules. For 0.1000000000000000055511151231257827021181583404541015625, the result of rounding 0.1 to a double, the range is [0.099999999999999998612221219218554324470460414886474609375,0.100000000000000012490009027033011079765856266021728515625].

Any double literal whose real number arithmetic value is in that range has the same double value as 0.1.

Double.toString(x) returns the String representation of the real number in the range that converts to x and has the fewest decimal places. Picking any real number in that range ensures that the round trip converting a double to a String using Double.toString and then converting the String back to a double using round-half-even rules recovers the original value.

System.out.println(0.100000000000000005); prints "0.1" because 0.100000000000000005 is in the range that rounds to the same double as 0.1, and 0.1 is the real number in that range with the fewest decimal places.

This effect is rarely visible because literals other than "0.1" with real number value in the range are rare. It is more noticeable for float because of the lesser precision. System.out.println(0.100000001f); prints "0.1".

Patricia Shanahan
  • 25,849
  • 4
  • 38
  • 75