BigDecimal compareTo不按预期工作
根据JavaDoc for BigDecimal
, 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()
函数似乎没有像我认为的那样工作。
这里发生了什么?
new BigDecimal(0.7)
不代表0.7。
它代表0.6999999999999999555910790149937383830547332763671875(确切地说)。
原因是double
字面0.7
并不完全代表0.7。
如果需要精确的 BigDecimal
值,则必须使用String
构造函数(实际上所有不采用double
值的构造函数都可以使用)。
尝试new BigDecimal("0.7")
。
BigDecimal(double)
构造函数的JavaDoc有一些相关的注释:
这个构造函数的结果可能有点不可预测。 有人可能会假设在Java中编写
new BigDecimal(0.1)
会创建一个BigDecimal
,它正好等于0.1(未缩放值为1,比例为1),但它实际上等于0.1000000000000000055511151231257827021181583404541015625。 这是因为0.1不能精确地表示为double
(或者,就此而言,作为任何有限长度的二进制分数)。 因此,传递给构造函数的值并不完全等于0.1,尽管有外观。另一方面,
String
构造函数是完全可预测的:写入new BigDecimal("0.1")
会创建一个BigDecimal
,它正好等于0.1,正如人们所期望的那样。 因此,通常建议使用String
构造函数优先于此构造函数 。当
double
必须用作BigDecimal
的源时,请注意此构造函数提供了精确的转换; 它不会产生与使用Double.toString(double)
方法将double
转换为String
然后使用BigDecimal(String)
构造函数相同的结果。 要获得该结果,请使用static
valueOf(double)
方法。
总结一下:如果要创建具有固定十进制值的BigDecimal
,请使用String
构造函数。 如果你已经有一个double
值,那么BigDecimal.valueOf(double)
将提供比使用new BigDecimal(double)
更直观的行为。