Answers:
A BigDecimal
是表示数字的精确方法。A Double
具有一定的精度。由于幅值之差太大,求和时使用各种大小的倍数(例如d1=1000.0
和d2=0.001
)可能会导致一起0.001
下降。有了BigDecimal
这不会发生。
这样做的缺点BigDecimal
是速度较慢,并且以这种方式编程算法会比较困难(由于+
-
*
并且/
没有过载)。
如果您要花钱,或必须精打细算,请使用BigDecimal
。否则Doubles
往往会足够好。
我确实建议您阅读Javadoc,BigDecimal
因为它们的解释确实比我在这里做的要好:)
if (Math.abs(loadPerServer - maxLoadPerServer) < 0.000001d) {
BigDecimal
”,则Double会具有更多的“精度”(更多数字)。
我的英语不好,所以我只在这里写一个简单的例子。
double a = 0.02;
double b = 0.03;
double c = b - a;
System.out.println(c);
BigDecimal _a = new BigDecimal("0.02");
BigDecimal _b = new BigDecimal("0.03");
BigDecimal _c = _b.subtract(_a);
System.out.println(_c);
程序输出:
0.009999999999999998
0.01
有人还是想使用double吗?;)
System.out.println(0.003f - 0.002f);
BigDecimal准确:System.out.println(new BigDecimal("0.003").subtract(new BigDecimal("0.002")));
与double有两个主要区别:
您应该使用BigDecimal进行货币计算的原因不是因为它可以表示任何数字,而是可以表示所有可以用十进制表示的数字,并且实际上包括货币世界中的所有数字(您永远不会转让1/3 $给某人)。
如果您写下一个小数,1 / 7
如十进制值,您将得到
1/7 = 0.142857142857142857142857142857142857142857...
具有无限个序列142857
。由于只能写有限数量的数字,因此不可避免地会引入舍入(或截断)错误。
像1/10
或1/100
表示为带有小数部分的二进制数的数字在小数点后也有无限个数字:
1/10 = binary 0.0001100110011001100110011001100110...
Doubles
将值存储为二进制,因此仅通过将十进制数转换为二进制数就可能会引入错误,甚至不执行任何算术运算。
BigDecimal
另一方面,十进制数字(如)按原样存储每个十进制数字。这意味着从一般意义上讲,十进制类型并不比二进制浮点数或定点类型更精确(即,在不1/7
损失精度的情况下不能存储),但是对于十进制数字有限的数字而言,它更准确。货币计算通常是这种情况。
Java的BigDecimal
另一个优点是,它可以在小数点的两侧具有任意(但有限)个数字,仅受可用内存限制。
BigDecimal是Oracle的任意精度数字库。BigDecimal是Java语言的一部分,可用于从财务到科学(即上午)的各种应用程序。
在某些计算中使用双精度数没有错。但是,假设您要计算Math.Pi * Math.Pi / 6,即实际参数为2(我正在研究的项目)的Riemann Zeta函数的值。浮点除法为您带来舍入误差的痛苦问题。
另一方面,BigDecimal包含许多用于以任意精度计算表达式的选项。在BigDecimal Java World中,Oracle文档下面所述的加,乘和除方法“代替” +,*和/:
http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html
compareTo方法在while和for循环中特别有用。
但是,在使用BigDecimal的构造函数时要小心。字符串构造函数在许多情况下非常有用。例如,代码
BigDecimal三分之一=新的BigDecimal(“ 0.33333333333”);
利用1/3的字符串表示形式以指定的精度表示该无限重复的数字。四舍五入错误很可能在JVM内部如此深处,以至于四舍五入错误不会干扰您的大多数实际计算。从我个人的经验来看,我发现四舍五入是逐渐增加的。从Oracle文档中可以看出,setScale方法在这些方面很重要。
/* * Portions Copyright IBM Corporation, 2001. All Rights Reserved. */
如果要进行计算,则应遵循有关如何计算和应使用的精度的法律。如果失败,那将是非法行为。唯一的真实原因是十进制大小写的位表示不精确。就像罗勒简单地说的那样,一个例子是最好的解释。只是为了补充他的示例,发生了以下情况:
static void theDoubleProblem1() {
double d1 = 0.3;
double d2 = 0.2;
System.out.println("Double:\t 0,3 - 0,2 = " + (d1 - d2));
float f1 = 0.3f;
float f2 = 0.2f;
System.out.println("Float:\t 0,3 - 0,2 = " + (f1 - f2));
BigDecimal bd1 = new BigDecimal("0.3");
BigDecimal bd2 = new BigDecimal("0.2");
System.out.println("BigDec:\t 0,3 - 0,2 = " + (bd1.subtract(bd2)));
}
输出:
Double: 0,3 - 0,2 = 0.09999999999999998
Float: 0,3 - 0,2 = 0.10000001
BigDec: 0,3 - 0,2 = 0.1
我们还有:
static void theDoubleProblem2() {
double d1 = 10;
double d2 = 3;
System.out.println("Double:\t 10 / 3 = " + (d1 / d2));
float f1 = 10f;
float f2 = 3f;
System.out.println("Float:\t 10 / 3 = " + (f1 / f2));
// Exception!
BigDecimal bd3 = new BigDecimal("10");
BigDecimal bd4 = new BigDecimal("3");
System.out.println("BigDec:\t 10 / 3 = " + (bd3.divide(bd4)));
}
给我们输出:
Double: 10 / 3 = 3.3333333333333335
Float: 10 / 3 = 3.3333333
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion
但:
static void theDoubleProblem2() {
BigDecimal bd3 = new BigDecimal("10");
BigDecimal bd4 = new BigDecimal("3");
System.out.println("BigDec:\t 10 / 3 = " + (bd3.divide(bd4, 4, BigDecimal.ROUND_HALF_UP)));
}
具有输出:
BigDec: 10 / 3 = 3.3333