BigDecimal compareTo无法按预期工作

时间:2011-05-19 12:57:58

标签: java bigdecimal

根据BigDecimal的{​​{3}},compareTo函数未考虑比较期间的比例。

现在我有一个看起来像这样的测试用例:

BigDecimal result = callSomeService(foo);
assertTrue(result.compareTo(new BigDecimal(0.7)) == 0); //this does not work
assertTrue(result.equals(new BigDecimal(0.7).setScale(10, BigDecimal.ROUND_HALF_UP))); //this works

我期望函数返回的值是0.7,其标度为10.打印该值会显示预期结果。但是compareTo()函数似乎没有像我认为的那样工作。

这里发生了什么?

1 个答案:

答案 0 :(得分:31)

new BigDecimal(0.7) 代表0.7。

代表0.6999999999999999555910790149937383830547332763671875(确切地说)。

原因是double文字0.7并不完全代表0.7。

如果您需要精确 BigDecimal值,必须使用String构造函数(实际上所有构造函数不要使用double值。)

请尝试new BigDecimal("0.7")

JavaDoc of the BigDecimal(double) constructor有一些相关的注释:

  
      
  1. 此构造函数的结果可能有些不可预测。有人可能会认为在Java中编写new BigDecimal(0.1)会创建一个BigDecimal,它恰好等于0.1(未缩放值为1,标度为1),但它实际上等于0.1000000000000000055511151231257827021181583404541015625。这是因为0.1不能精确地表示为double(或者,就此而言,作为任何有限长度的二进制分数)。因此,传递给构造函数的值并不完全等于0.1,尽管有外观。

  2.   
  3. 另一方面,String构造函数是完全可预测的:写new BigDecimal("0.1")创建一个BigDecimal 完全等于0.1,正如人们所料。因此,通常建议优先使用String constructor

  4.   
  5. 如果必须将double用作BigDecimal的来源,请注意此构造函数提供了精确的转换;它与使用Double.toString(double)方法将double转换为String然后使用BigDecimal(String)构造函数的结果不同。要获得该结果,请使用static valueOf(double)方法。

  6.   

总结一下:如果要创建具有固定十进制值的BigDecimal,请使用String构造函数。如果已经 double值,那么BigDecimal.valueOf(double)将提供比使用new BigDecimal(double)更直观的行为。