我什么时候可以在Java中使用浮点类型进行货币计算?

时间:2012-08-08 18:14:18

标签: java math floating-point computer-architecture

我了解到我不能在Java中使用浮点类型(float / double来进行货币计算(以及当我需要精确结果时的任何其他计算)。我必须使用decimal数字类型(Java中为BigDecimal)。

现在,当我可以使用浮点类型时,我会变得更聪明。他们提供任何精确保证吗?假设我想要精确计算一些公式0.001。我如何知道我是否可以使用浮点类型进行此计算?

5 个答案:

答案 0 :(得分:7)

当您可以演示应用程序可接受的结果时,您可以使用Java或其他语言的浮点类型。

使用BigDecimal本身并不能解决这个问题。例如,假设一个银行账户包含87.34美元,并且您必须在一年内增加利息,并且年利率为2.37%。首先,BigDecimal不会正确计算月利率,因为您必须将2.37%除以12,并且2.37 / 12(或。0237/12)不能用十进制表示。其次,即使BigDecimal确实正确计算了月利率,并且正确地计算了87.34美元的利息,您可能仍需要将该数额四舍五入到一定数量的美分,然后再将其添加到余额中。可以在某些法律文档中指定该舍入的规则,并且可能与BigDecimal舍入的方式不匹配。

十进制浮点和二进制浮点都能够精确计算许多结果,比您在示例中建议的.001精度更精确。当以各种方式使用时,两者都能够产生重大错误。

因此,要使用浮点数,您必须了解类型可以表示的值,浮点运算中发生的错误,要执行的操作以及应用程序所需的操作。通常,可以通过仔细制作操作来避免浮点错误。例如,您可以通过将金额缩放为整数值来处理货币(使用8734表示$ 87.34而不是使用87.34表示87.34)。作为另一个例子,您可以证明来自多个操作的累积误差小于半分,因此您可以执行操作并将最终结果舍入到最接近的分数,这将是正确的,因为错误从未足够大使最终答案不正确。

答案 1 :(得分:2)

  

我了解到我不能使用浮点类型(Java中的float / double)进行货币计算

您无法使用double准确地代表超过70万亿美元的资金。对于小于此值的值,您可以使用doublelong而不会出错(假设您使用了适当的舍入方式)

一旦您了解了舍入的需要,使用double的恕我直言就更容易使用了。

然而,许多人认为它容易出错,因为您不知道谁可能需要维护代码。使用BigDecimal将确保您正确使用舍入,并为您提供有关其工作方式的多种选项。

许多人觉得令人不安的是,即使0.1也没有精确表示,BigDecimal可以显示确切的表示(以及为什么你必须小心你如何转换为BigDecimal)

System.out.println(new BigDecimal(0.1));

打印

0.1000000000000000055511151231257827021181583404541015625

许多人无效地使用

new BigDecimal(Double.toString(0.1))

或类似的工作,但具有讽刺意味的只是他们试图避免使用的toString方法准确。

更有效的方法是

BigDecimal.valueOf(0.1)

避免了创建String的需要。

支持double的库会正确显示此数字,但只要您执行计算,默认轮次可能就不够了。

System.out.println(0.1 * 3);

打印

0.30000000000000004

在这种情况下,你必须说出你期望的精确度。假设你有可以使用的美元和美分

System.out.printf("%.2f%n", 0.1 * 3); // round output to two decimal places

打印

0.30

找到你不能再继续添加0.01

的地方
for (double d = 1; d < Long.MAX_VALUE; d *= 2) {
    long l = Double.doubleToLongBits(d);
    double d1 = Double.longBitsToDouble(l + 1);
    if (d1 - d > 0.01) {
        System.out.println("Cannot represent " + d + " plus 0.01");
        double d_1 = Double.longBitsToDouble(l - 1);
        if (d - d_1 < 0.01)
            System.out.println("Can represent " + d + " minus 0.01");
        break;
    }
}

打印

Cannot represent 7.0368744177664E13 plus 0.01
Can represent 7.0368744177664E13 minus 0.01

答案 2 :(得分:1)

  

假设我想计算一些精度为0.001的公式。我如何知道我是否可以使用浮点类型进行此计算?

浮点类型是base-2,而不是base-10。 1 /(10 ^ n)不能用(二进制)浮点数精确表示,很像1/3不能用十进制数精确表示。浮点数对于科学类型计算很有用,其中值可能很大或很小,并且测量的不确定性使计算机的精度限制相形见绌。浮点运算在支持它的硬件上非常快,而其他非整数类型则不是那么快。

浮点数是所谓的,因为小数点每一侧的位数将根据数量而变化。浮点数基本上表示为+/- 1.a * 2^b,其中ab是基数为2的数字。这类似于基于小数的Scientific Notation 1.a * 10^b。有关IEEE 754浮点的详细信息,请参阅Wikipedia文章。

答案 3 :(得分:1)

此视频刚刚介绍了此主题:

http://www.youtube.com/watch?v=PZRI1IfStY0

对于浮点运算的“问题”,它是一个优秀且易于理解的描述。他们还提到了浮点数货币计算的问题。

答案 4 :(得分:-1)

浮点类型与硬件有关,因此没有一般的精度保证。当结果不需要“完美”时,你可以使用它们。

请参阅:http://en.wikipedia.org/wiki/Pentium_FDIV_bug

来自维基百科:(http://en.wikipedia.org/wiki/Floating_point

浮点数

~7.2小数

〜15.9 deciamls for double

这意味着句号的位置并不重要,数字中的精确数字总是有限的。