Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/373.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
什么时候可以在Java中使用浮点类型进行货币计算?_Java_Math_Floating Point_Computer Architecture - Fatal编程技术网

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

什么时候可以在Java中使用浮点类型进行货币计算?,java,math,floating-point,computer-architecture,Java,Math,Floating Point,Computer Architecture,我了解到我不能使用浮点类型(Java中的浮点类型(float/double)进行货币计算(以及需要精确结果时的任何其他计算)。我必须使用decimal数字类型(Java中的BigDecimal) 现在,当我可以使用浮点类型时,我就不知道了。他们是否提供任何精度保证?假设我想用精度0.001计算一些公式。如何知道是否可以使用浮点类型进行此计算?浮点类型取决于硬件,因此没有一般精度保证。当结果不需要“完美”时,您可以使用它们 见: 来自维基百科:() 浮点数约7.2位小数 双精度约15.9分贝 这意

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


现在,当我可以使用浮点类型时,我就不知道了。他们是否提供任何精度保证?假设我想用精度
0.001
计算一些公式。如何知道是否可以使用浮点类型进行此计算?

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

见:

来自维基百科:()

浮点数约7.2位小数

双精度约15.9分贝

这意味着周期在哪里并不重要,一个数字中的精确数字总是有限的

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

您不能使用
double
来准确表示超过70万亿美元的货币。对于小于此值的值,可以使用
double
long
而不会出现错误(前提是使用适当的舍入)

一旦您了解四舍五入的必要性,使用
double
的IMHO就更容易使用

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

许多人感到不安的是,即使
0.1
也不能精确表示,而BigDecimal可以显示精确的表示(以及为什么必须小心转换为BigDecimal)

印刷品

0.1000000000000000055511151231257827021181583404541015625
0.30000000000000004
0.30
Cannot represent 7.0368744177664E13 plus 0.01
Can represent 7.0368744177664E13 minus 0.01
许多人使用不当

new BigDecimal(Double.toString(0.1))
或者类似的方法,但具有讽刺意味的是,它的准确度仅与他们试图避免使用的toString方法一样

更有效的方法是

BigDecimal.valueOf(0.1)
这样就不需要创建字符串

支持
double
的库将正确显示此数字,但一旦您执行计算,默认轮数可能不够

System.out.println(0.1 * 3);
印刷品

0.1000000000000000055511151231257827021181583404541015625
0.30000000000000004
0.30
Cannot represent 7.0368744177664E13 plus 0.01
Can represent 7.0368744177664E13 minus 0.01
在这种情况下,你必须说出你期望的精度。说你有美元和美分可以用

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

0.1000000000000000055511151231257827021181583404541015625
0.30000000000000004
0.30
Cannot represent 7.0368744177664E13 plus 0.01
Can represent 7.0368744177664E13 minus 0.01

查找无法继续添加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;
    }
}
假设我想计算一个精度为0.001的公式。如何知道是否可以使用浮点类型进行此计算

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


浮点数之所以被称为浮点数,是因为小数点两侧的位数会因数字而异。浮点数基本上表示为
+/-1.a*2^b
,其中
a
b
是以2为基数的数字。这类似于基于十进制的
1.a*10^b
。有关浮点的更多信息,请参阅Wikipedia文章。

当您可以证明结果适用于您的应用程序时,您可以在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)。另一个例子是,您可以证明几个操作的累积误差小于半美分,因此您可以执行这些操作并将最终结果四舍五入到最接近的美分,这是正确的,因为错误永远不会大到导致最终答案不正确。

这段视频刚刚涉及到这个主题:


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

您可以使用assert语句通过从精确值中减去计算值来检查精度。但这只会在测试时有所帮助。你只需要学习如何有效地使用浮点数。即使是
0.1
也不能精确地表示为浮点数