问题
The second of below method calls, to setYCoordinate(), gets incorrect value -89.99999435599995 instead of -89.99999435599994.
The first call to setXCoordinate() gets correct value 29.99993874900002.
setXCoordinate(BigDecimal.valueOf(29.99993874900002))
setYCoordinate(BigDecimal.valueOf(-89.99999435599994))
I put a breakpoint inside BigDecimal.valueOf() - this method's code looks as below -
public static BigDecimal valueOf(double val) {
// Reminder: a zero double returns '0.0', so we cannot fastpath
// to use the constant ZERO. This might be important enough to
// justify a factory approach, a cache, or a few private
// constants, later.
return new BigDecimal(Double.toString(val));
}
The argument received by valueOf i.e. "double val" itself is -89.99999435599995 when inspected. Why? I have Java version set as below in my Maven pom.xml
<java.version>1.8</java.version>
回答1:
Because a double
can't retain that much precision; you shouldn't use a double
, but rather a String
when initializing your BigDecimal
:
new BigDecimal("29.99993874900002");
new BigDecimal("-89.99999435599994");
See: Is floating point math broken?
回答2:
Your confusion has nothing to do with BigDecimal
.
double d = -89.99999435599994;
System.out.println(d); //or inspecting it in a debugger
yields:
-89.99999435599995
This is just the way doubles
work in java, in combination with the way Double.toString defines the String
-representation. This conversion happens before any method is invoked, when the literal is interpreted as double
. The details are specified in JLS Chapter 3.10.2. Floating-Point Literals and the JavaDocs of Double.valueOf(String).
If you need to express the value -89.99999435599994
as BigDecimal
, the easiest way is to use the constructor taking a String, as other answers have already pointed out:
BigDecimal bd = new BigDecimal("-89.99999435599994");
BigDecimal bd = new BigDecimal("-89.99999435599994");
System.out.println(bd);
yields:
-89.99999435599994
回答3:
You're right on the edge of precision for a double-precision floating point value, with 16 digits specified, and there's just shy of a full 16 digits of decimal accuracy available. If you skip BigDecimal entirely, just set a double to -89.99999435599994 and print it back out, you'll get -89.99999435599995.
来源:https://stackoverflow.com/questions/51371109/bigdecimal-double-precision-number-rounds-up-higher