BigDecimal compareTo无法按预期工作

Aks*_*hay 13 java bigdecimal

根据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
Run Code Online (Sandbox Code Playgroud)

我期望函数返回的值是,0.7并且具有10的标度.打印该值显示预期结果.但是这个compareTo()功能似乎并没有像我认为的那样工作.

这里发生了什么?

Joa*_*uer 31

new BigDecimal(0.7)没有代表0.7.

它代表0.6999999999999999555910790149937383830547332763671875(确切地说).

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

如果需要精确 BigDecimal值,则必须使用String构造函数(实际上所有不带double值的构造函数都可以使用).

试试吧new BigDecimal("0.7").

构造函数JavaDocBigDecimal(double)有一些相关的注释:

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

  2. String构造,在另一方面,是完全可以预测的:写作new BigDecimal("0.1")产生了BigDecimal恰好等于0.1,正如人们所期望的那样.因此,通常建议优先使用String构造函数.

  3. 当a double必须用作a的源时BigDecimal,请注意此构造函数提供了精确的转换; 它没有给出与使用方法转换double为a 然后使用构造函数相同的结果.要获得该结果,请使用该方法.StringDouble.toString(double)BigDecimal(String)static valueOf(double)

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