2012-05-15 39 views
2

最近,我问一个关于Java的怪异双楼舍入的问题,并得到了答案使用BigDecimals的代替,所以尝试了下面的代码:的BigDecimal楼舍入出错

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?

+0

如果您将问题从舍入问题转换为乘法问题,为什么要保留错误的标题? –

回答

3

的问题就在这里:

BigDecimal velocity = new BigDecimal(-0.07); 

-0.07不能准确地为double表示,因此传递给BigDecimal构造文本值最终被超过-0.07略有不同。 BigDecimal只需要这个近似值并与它一起运行,产生你看到的结果。

尝试:

BigDecimal velocity = new BigDecimal(-7, 2); 
BigDecimal afterMultiplyingBy200 = velocity.multiply(new BigDecimal(2, -2)); 
5

从我这个问题的答案:

当代码被编译或解释,你的“0.1”已经是 四舍五入到该格式的最接近的数字,这导致小 舍入误差甚至在计算发生之前。

的问题是,new BigDecimal(-0.07);使用double文本初始化该BigDecimal - 这样的错误仍然发生。使用BigDecimal构造函数代替String

2

您应该使用string constructor以避免舍入误差由于使用了双打:

constructor using doubles
BigDecimal velocity = new BigDecimal("-0.07"); 
BigDecimal afterMultiplyingBy200 = velocity.multiply(new BigDecimal("200")); 

的Javadoc提取物 - 重点煤矿:

  1. 此构造方法的结果有点不可预测。有人可能会认为在Java中编写新的BigDecimal(0.1)会创建一个正好等于0.1的BigDecimal(非缩放值为1,标度为1),但实际上它等于0.1000000000000000055511151231257827021181583404541015625。这是因为0.1不能完全表示为双(或者就此而言,作为任何有限长度的二进制分数)。因此,传递给构造函数的值并不完全等于0.1,尽管如此。
  2. 另一方面,String构造函数完全可以预测:编写新的BigDecimal(“0.1”)会创建一个精确等于0.1的BigDecimal,正如人们所期望的那样。因此,通常建议使用字符串构造函数优先于此。