NumberFormat Parse Issue
Asked Answered
M

2

3

I am quite confused about this peculiar 'error' I am getting when parsing a String to a Double.

I've already set up the NumberFormat properties and symbols.

When passing a String with 15 digits and 2 decimals (ex. str = "333333333333333,33") and parsing it with Number num = NumberFormat.parse(str) the result is omitting a digit.

The actual value of num is 3.333333333333333E14.

It seems to be working with Strings with all 1's, 2's and 4's though...

Anyone can enlighten me?

Cheers Enrico

Melanson answered 16/8, 2011 at 9:33 Comment(0)
E
6

The short answer; due to round error

(double) 111111111111111.11 != (double) 111111111111111.1

but

(double) 333333333333333.33 == (double) 333333333333333.3

If you want more precision, use setParseBigDecimal and parse will return a BigDecimal.


Why does this happen? This is because you are at the limit of the precision of double. The 17 ones is fine as it can just be represented. The 2's is just double this and as double stores powers of two, every power of two of all 17 ones, so 17 fours and 17 eights is fine.

However, 17 threes takes one more bit than double has to represent the value and this last bit is truncated. Similarly 17 fives, sixes and nines also have rounding errors.

double[] ds = {
        111111111111111.11,
        222222222222222.22,
        333333333333333.33,
        444444444444444.44,
        555555555555555.55,
        666666666666666.66,
        777777777777777.77,
        888888888888888.88,
        999999999999999.99};
for (double d : ds) {
    System.out.println(d + " - " + new BigDecimal(d));
}

prints the following. The double is rounded slightly before printing and the BigDecimal shows you the exact values the double represents.

1.1111111111111111E14 - 111111111111111.109375
2.2222222222222222E14 - 222222222222222.21875
3.333333333333333E14 - 333333333333333.3125
4.4444444444444444E14 - 444444444444444.4375
5.5555555555555556E14 - 555555555555555.5625
6.666666666666666E14 - 666666666666666.625
7.777777777777778E14 - 777777777777777.75
8.888888888888889E14 - 888888888888888.875
1.0E15 - 1000000000000000
Extemporaneous answered 16/8, 2011 at 9:51 Comment(3)
@aioobe, Coming from you, that means something. ;)Extemporaneous
heh thanks :-) I was so surprised over your second expression so I wrote a followup questionAnderer
...which turned out to have an obvious answer :-/ slightly embarrassed.Anderer
A
5

The DecimalFormat.parse method will in this case return a Double, which has limited precision.

You can't expect it to always be able to return a Number that represents the input exactly.

You can use BigDecimal.setParseBigDecimal to allow the number format to return a BigDecimal from the parse method. This Number is capable of representing your values with arbitrary precision. (Thanks @Peter Lawrey for pointing that out!)

Anderer answered 16/8, 2011 at 9:38 Comment(4)
Is there a workaround to make it not parse to double but leave it to long?Melanson
A long is an integer type, thus you would loose the fractional part (,33).Anderer
@aioobe, Could you be looking at the docs for Java 1.4? This method was added in Java 5.0. download.oracle.com/javase/6/docs/api/java/text/…Extemporaneous
You're welcome. Be sure to mark @Peter Lawreys great answer as accepted by clicking the checkbox.Anderer

© 2022 - 2024 — McMap. All rights reserved.