losing precision converting from java BigDecimal to double

后端 未结 5 1473
遥遥无期
遥遥无期 2020-12-15 08:56

I am working with an application that is based entirely on doubles, and am having trouble in one utility method that parses a string into a double. I\'ve found a fix where

5条回答
  •  Happy的楠姐
    2020-12-15 09:52

    You've reached the maximum precision for a double with that number. It can't be done. The value gets rounded up in this case. The conversion from BigDecimal is unrelated and the precision problem is the same either way. See this for example:

    System.out.println(Double.parseDouble("299792.4579999984"));
    System.out.println(Double.parseDouble("299792.45799999984"));
    System.out.println(Double.parseDouble("299792.457999999984"));
    

    Output is:

    299792.4579999984
    299792.45799999987
    299792.458
    

    For these cases double has more than 3 digits of precision after the decimal point. They just happen to be zeros for your number and that's the closest representation you can fit into a double. It's closer for it to round up in this case, so your 9's seem to disappear. If you try this:

    System.out.println(Double.parseDouble("299792.457999999924"));
    

    You'll notice that it keeps your 9's because it was closer to round down:

    299792.4579999999
    

    If you require that all of the digits in your number be preserved then you'll have to change your code that operates on double. You could use BigDecimal in place of them. If you need performance then you might want to explore BCD as an option, although I'm not aware of any libraries offhand.


    In response to your update: the maximum exponent for a double-precision floating-point number is actually 1023. That's not your limiting factor here though. Your number exceeds the precision of the 52 fractional bits that represent the significand, see IEEE 754-1985.

    Use this floating-point conversion to see your number in binary. The exponent is 18 since 262144 (2^18) is nearest. If you take the fractional bits and go up or down one in binary, you can see there's not enough precision to represent your number:

    299792.457999999900 // 0010010011000100000111010100111111011111001110110101
    299792.457999999984 // here's your number that doesn't fit into a double
    299792.458000000000 // 0010010011000100000111010100111111011111001110110110
    299792.458000000040 // 0010010011000100000111010100111111011111001110110111
    

提交回复
热议问题