我总是被告知永远不要用双类型或浮点类型来表示货币,这一次我向你提出一个问题:为什么?

我相信有一个很好的理由,我只是不知道是什么。


当前回答

美国货币可以很容易地用美元和美分来表示。整数是100%精确的,而浮点二进制数并不完全匹配浮点小数。

其他回答

美国货币可以很容易地用美元和美分来表示。整数是100%精确的,而浮点二进制数并不完全匹配浮点小数。

The result of floating point number is not exact, which makes them unsuitable for any financial calculation which requires exact result and not approximation. float and double are designed for engineering and scientific calculation and many times doesn’t produce exact result also result of floating point calculation may vary from JVM to JVM. Look at below example of BigDecimal and double primitive which is used to represent money value, its quite clear that floating point calculation may not be exact and one should use BigDecimal for financial calculations.

    // floating point calculation
    final double amount1 = 2.0;
    final double amount2 = 1.1;
    System.out.println("difference between 2.0 and 1.1 using double is: " + (amount1 - amount2));

    // Use BigDecimal for financial calculation
    final BigDecimal amount3 = new BigDecimal("2.0");
    final BigDecimal amount4 = new BigDecimal("1.1");
    System.out.println("difference between 2.0 and 1.1 using BigDecimal is: " + (amount3.subtract(amount4)));

输出:

difference between 2.0 and 1.1 using double is: 0.8999999999999999
difference between 2.0 and 1.1 using BigDecimal is: 0.9

如果你的计算涉及到不同的步骤,任意的精度算法都不能100%覆盖你。

使用完美的结果表示(使用自定义Fraction数据类型,将除法操作批处理到最后一步)并且仅在最后一步转换为十进制的唯一可靠方法。

任意精度不会有帮助,因为总有可能有很多小数点后的数字,或者一些结果,如0.6666666……最后一个例子没有任意的表示法。所以每一步都会有小误差。

这些错误会累积起来,最终可能变得不再容易被忽视。这被称为错误传播。

我将冒着被否决的风险,但我认为浮点数在货币计算中的不适用性被高估了。只要确保正确地进行了舍入,并且有足够的有效数字来处理zneak解释的二进制十进制表示不匹配,就不会有问题。

在Excel中使用货币计算的人总是使用双精度浮点数(Excel中没有货币类型),我还没有看到有人抱怨舍入错误。

当然,你必须在合理范围内;例如,一个简单的网络商店可能永远不会遇到双精度浮点数的任何问题,但如果你做会计或其他需要添加大量(无限制)数字的事情,你不会想要用十英尺的杆子触摸浮点数。

这个问题的许多答案都讨论了IEEE和围绕浮点算法的标准。

我的背景不是计算机科学(物理和工程),我倾向于从不同的角度看问题。对我来说,我在数学计算中不使用double或float的原因是我会丢失太多的信息。

有什么替代方案?有很多(还有很多我不知道的!)

Java中的BigDecimal原产于Java语言。 Apfloat是另一个用于Java的任意精度库。

c#中的十进制数据类型是微软的. net中28位有效数字的替代方案。

SciPy (Scientific Python)可能还可以处理财务计算(我还没有尝试过,但我怀疑是这样)。

GNU多精度库(GMP)和GNU MFPR库是C和c++的两个免费的开源资源。

还有用于JavaScript(!)和PHP的精确数值库,我认为它们可以处理财务计算。

对于许多计算机语言,也有专有的(特别是Fortran)和开源的解决方案。

我不是训练出来的计算机科学家。然而,我倾向于在Java中使用BigDecimal,在c#中使用decimal。我还没有尝试过我列出的其他解决方案,但它们可能也非常好。

对我来说,我喜欢BigDecimal是因为它支持的方法。c#的十进制非常好,但我还没有机会尽可能多地使用它。我在业余时间做我感兴趣的科学计算,BigDecimal似乎工作得很好,因为我可以设置浮点数的精度。BigDecimal的缺点是什么?它有时会很慢,特别是当你使用除法的时候。

为了提高速度,您可以查看C、c++和Fortran中的免费和专有库。