BigDecimal/double 精度 - 数字向上取整

BigDecimal/double Precision - number rounds up higher

下面的第二个方法调用 setYCoordinate() 得到不正确的值 -89.99999435599995 而不是 -89.99999435599994。

第一次调用 setXCoordinate() 得到正确的值 29.99993874900002。

setXCoordinate(BigDecimal.valueOf(29.99993874900002))
setYCoordinate(BigDecimal.valueOf(-89.99999435599994))

我在 BigDecimal.valueOf() 中放置了一个断点 - 此方法的代码如下所示 -

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));
    }

valueOf 收到的参数,即 "double val" 本身在检查时为 -89.99999435599995。为什么?我的 Java 版本在我的 Maven pom.xml

中设置如下
<java.version>1.8</java.version>

因为 double 无法保持那么高的精度;在初始化 BigDecimal:

时,你不应该使用 double,而应该使用 String
new BigDecimal("29.99993874900002");
new BigDecimal("-89.99999435599994");

参见:Is floating point math broken?

您正处于双精度浮点值的精度边缘,指定了 16 位数字,并且可用的小数精度只有 16 位数字。如果您完全跳过 BigDecimal,只需将双精度设置为 -89.99999435599994 并将其打印出来,您将得到 -89.99999435599995。

你的困惑与BigDecimal无关。

double d = -89.99999435599994;
System.out.println(d); //or inspecting it in a debugger

产量:

-89.99999435599995

这正是 doubles 在 java 中的工作方式,结合 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).

的方式

如果您需要将值 -89.99999435599994 表示为 BigDecimal,最简单的方法是使用 constructor taking a String,其他答案已经指出:

BigDecimal bd = new BigDecimal("-89.99999435599994");

BigDecimal bd = new BigDecimal("-89.99999435599994");
System.out.println(bd);

产量:

-89.99999435599994