【问题标题】:BigDecimal compareTo not working as expectedBigDecimal compareTo 未按预期工作
【发布时间】:2011-05-19 12:57:58
【问题描述】:

根据BigDecimalJavaDoccompareTo函数在比较时不考虑比例。

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

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() 函数似乎并没有按照我认为的方式工作。

这是怎么回事?

【问题讨论】:

  • 期望该值为 0.7,但您确定吗?您是否尝试过让 callSomeService 简单地返回 new BigDecimal(0.7)?
  • @CPerkins 是的,对此非常确定。我打印了结果,equals 方法也有效。反正问题解决了:)
  • 这也让我感到困惑,直到我明白我是从 DOUBLE 创建 BigDecimal... :-\

标签: java bigdecimal


【解决方案1】:

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) 会创建一个恰好等于 0.1 的 BigDecimal(未缩放的值 1,缩放为 1),但它实际上等于 0.1000000000000000055511151231257827021181583404541015625。这是因为 0.1 不能完全表示为 double(或者,就此而言,不能表示为任何有限长度的二进制分数)。因此,传递给构造函数的值并不完全等于 0.1,尽管看起来如此。

  2. 另一方面,String 构造函数是完全可预测的:编写new BigDecimal("0.1") 会创建一个BigDecimal,它完全 等于0.1,正如人们所期望的那样。因此,一般建议优先使用String constructor而不是这个。

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

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

【讨论】:

    猜你喜欢
    • 2021-06-04
    • 2022-01-24
    • 2015-05-11
    • 2020-05-15
    • 2014-10-31
    • 2018-02-12
    • 2014-01-20
    • 2015-01-13
    • 2013-08-01
    相关资源
    最近更新 更多