【问题标题】:Why are 0.4 and 0.40 different as BigDecimal? [duplicate]为什么 0.4 和 0.40 与 BigDecimal 不同? [复制]
【发布时间】:2019-06-28 10:33:52
【问题描述】:

我读到 BigDecimal 是用 Java 表示货币时要走的路。

但我不明白为什么我的一个单元测试失败并显示以下消息:

org.opentest4j.AssertionFailedError:   
Expected :0.40  
Actual   :0.4

“实际”值是BigDecimal.valueOf(0.398).setScale(2, RoundingMode.HALF_UP) 的结果。

所以我想我的问题有两个部分:

  1. 为什么这些值不相等?
  2. 如何以不会触发这种不匹配的方式将 0.40 美元表示为 BigDecimal?

【问题讨论】:

  • 根据 javadocs 将此 BigDecimal 与指定的 Object 进行比较是否相等。与 compareTo 不同,此方法仅当两个 BigDecimal 对象的值和比例相等时才认为它们相等(因此,通过此方法进行比较时,2.0 不等于 2.00)。
  • 0.40 表示你已经测量到百位,并且你确定的百位是00.4 表示您测量到百位,并且您百位值是多少。
  • 也可以试试compareTo
  • 不,你应该使用assertEquals(0, actualBigDecimal.compareTo(expectedBigDecimal));

标签: java junit


【解决方案1】:

BigDecimals 是数字和“比例”的组合。除非两者相等,否则 2 BD 不认为自己相等。我建议使用.compareTo(other) == 0) 来获得答案。

注意:我不认为使用 BD 是做货币的好方法。

通常有两种处理货币的方法。简单的方法和困难的方法。

简单的方法是将美分存储在intlong 中。因此,将 0.40 美元存储为简单的40,而像 12.50 美元这样的东西将存储为1250。您现在有 2 个问题:您不能代表半美分,并且可能会发生溢出(您不能代表高于 2^31-1 美分的金额,但那是......很多美分。让它成为 @987654326 @ 并且我们远远超过了整个世界的 GDP)。

但是,半美分通常是个问题。拿这个问题:

我有 4 美分。我希望将这些分成 3 个人。

那么,我们该怎么办? BigDecimal 在这里帮不了你;你不能用完美的 BD 来表示 4 除以 3。你必须在某个地方四舍五入(它是 1.33333333...BD 不能代表无限序列)。即使它可以,或者您决定以惊人的数量进行舍入(比如说 200 位数),现在该怎么办?你不能告诉你的银行转账三分之一美分。没有简单的答案:如果这是您的应用程序需要做的,那么您需要决定如何处理。例如,“剩余的一分钱是给房子的”或“软件随机选择一个收件人;他们得到 2 美分,另外 2 人得到 1 美分)。

换句话说,如果“只使用 int/long”不这样做,那么 BigDecimal 也不好。

【讨论】:

  • 3人分4美分根本没有答案。 BigDecimal 的行为与这里的银行完全一样。
  • 我猜想使用long 可能会迫使开发人员面临四美分问题等四舍五入问题,而使用BigDecimal 可以让他们在不考虑后果的情况下愉快地分开。措辞恰当的答案。
  • @user207421 确实,这正是我的观点:使用 BD 并不是解决所有问题的灵丹妙药。使用 BD 比仅仅用一个长的表示美分要复杂得多,我试图告诉 OP,这种额外的复杂性通常是不值得的。
猜你喜欢
  • 1970-01-01
  • 2016-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多