Java 大十进制地板舍入出错

Java 大十进制地板舍入出错,java,bigdecimal,rounding,Java,Bigdecimal,Rounding,我最近问了一个关于奇怪的java双底舍入的问题,得到了使用大小数的答案,因此尝试了以下代码: BigDecimal velocity = new BigDecimal(-0.07); BigDecimal afterMultiplyingBy200 = velocity.multiply( new BigDecimal(200.0) ); BigDecimal floored = afterMultiplyingBy200.setScale(0, RoundingMode.FLOOR); Sys

我最近问了一个关于奇怪的java双底舍入的问题,得到了使用大小数的答案,因此尝试了以下代码:

BigDecimal velocity = new BigDecimal(-0.07);
BigDecimal afterMultiplyingBy200 = velocity.multiply( new BigDecimal(200.0) );
BigDecimal floored = afterMultiplyingBy200.setScale(0, RoundingMode.FLOOR);
System.out.println("After multiplication " + afterMultiplyingBy200);
System.out.println("floored value is " + floored);
我得到了以下结果

After multiplication -14.000000000000001332267629550187848508358001708984375000
floored value is -15

似乎即使使用BigDecimal,我也无法得到-0.07乘以200的正确值,我能做些什么来精确得到-14.0吗?

问题就在这里:

BigDecimal velocity = new BigDecimal(-0.07);
-0.07
不能精确地表示为
双精度
,因此传递给
BigDecimal
构造函数的文本值最终与
-0.07
略有不同
BigDecimal
只需获取该近似值并使用它运行,即可生成您看到的结果

尝试:


你应该看一下,特别是我对这个问题的回答中的
一半

当编译或解释代码时,您的“0.1”已被删除 按该格式四舍五入到最接近的数字,这将导致较小的 甚至在计算之前就存在舍入误差

问题是
newbigdecimal(-0.07)
使用一个
double
文本来初始化
BigDecimal
——因此错误仍然会发生。请使用采用
字符串的
BigDecimal
构造函数。

您应该使用,以避免由于使用双精度字符而产生舍入错误:

BigDecimal velocity = new BigDecimal("-0.07");
BigDecimal afterMultiplyingBy200 = velocity.multiply(new BigDecimal("200"));
重点矿井的Javadoc摘录:

  • 此构造函数的结果可能有些不可预测。可以假设,在Java中编写新的BigDecimal(0.1)会创建一个完全等于0.1的BigDecimal(无标度值1,标度为1),但实际上等于0.10000000000000055115123125782702118158340451015625。这是因为0.1不能精确地表示为双精度(或者,就此而言,表示为任何有限长度的二进制分数)。因此,传递给构造函数的值并不完全等于0.1,尽管如此
  • 另一方面,字符串构造函数是完全可预测的:编写新的BigDecimal(“0.1”)会创建一个完全等于0.1的BigDecimal,正如人们所期望的那样。因此,通常建议优先使用字符串构造函数
    根据,
    ROUND\u FLOOR
    向负无穷大方向旋转,从而将
    -14.000…
    四舍五入到
    -15

    如果您将问题从四舍五入问题更改为乘法问题,为什么要保留错误的标题?
    BigDecimal velocity = new BigDecimal("-0.07");
    BigDecimal afterMultiplyingBy200 = velocity.multiply(new BigDecimal("200"));