我了解到我不能在Java中使用浮点类型(float
/ double
来进行货币计算(以及当我需要精确结果时的任何其他计算)。我必须使用decimal
数字类型(Java中为BigDecimal
)。
现在,当我可以使用浮点类型时,我会变得更聪明。他们提供任何精确保证吗?假设我想要精确计算一些公式0.001
。我如何知道我是否可以使用浮点类型进行此计算?
答案 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万亿美元的资金。对于小于此值的值,您可以使用double
或long
而不会出错(假设您使用了适当的舍入方式)
一旦您了解了舍入的需要,使用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
,其中a
和b
是基数为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
这意味着句号的位置并不重要,数字中的精确数字总是有限的。