我必须计算一些浮点变量,我的同事建议我使用BigDecimal而不是double,因为它会更精确。但我想知道它是什么,以及如何最大限度地利用BigDecimal?
当前回答
它与double有两个主要区别:
任意精度,与BigInteger类似,它们可以包含任意精度和大小的数量(而double具有固定的位数) BigDecimal以10为底,而不是以2为底,BigDecimal是n*10^-scale,其中n是任意的有符号大整数,刻度可以被认为是小数点向左或向右移动的位数
说BigDecimal可以表示任何数字仍然是不正确的。但是你应该使用BigDecimal进行货币计算的两个原因是:
它可以表示所有可以用十进制表示的数字,包括货币世界中几乎所有的数字(你永远不会把1/3美元转给某人)。 精度可控制,避免累积误差。对于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吗?;)
BigDecimal是一种表示数字的精确方法。替身有一定的精确度。处理不同大小的双精度值(例如d1=1000.0和d2=0.001)可能会导致在求和时由于大小差异太大而将0.001一并删除。使用BigDecimal就不会发生这种情况。
BigDecimal的缺点是速度较慢,并且以这种方式编程算法有点困难(由于+ - *和/没有重载)。
如果你处理的是金钱,或者精度是必须的,使用BigDecimal。否则双打就足够了。
我建议你阅读BigDecimal的javadoc,因为他们比我在这里解释得更好:)
它与double有两个主要区别:
任意精度,与BigInteger类似,它们可以包含任意精度和大小的数量(而double具有固定的位数) BigDecimal以10为底,而不是以2为底,BigDecimal是n*10^-scale,其中n是任意的有符号大整数,刻度可以被认为是小数点向左或向右移动的位数
说BigDecimal可以表示任何数字仍然是不正确的。但是你应该使用BigDecimal进行货币计算的两个原因是:
它可以表示所有可以用十进制表示的数字,包括货币世界中几乎所有的数字(你永远不会把1/3美元转给某人)。 精度可控制,避免累积误差。对于double,随着值的大小增加,其精度降低,这可能会在结果中引入重大误差。
BigDecimal是Oracle的任意精度数值库。BigDecimal是Java语言的一部分,对于从金融到科学的各种应用程序都很有用。
在某些计算中使用double并没有错。但是,假设您想计算数学。π *数学。Pi / 6,也就是黎曼ζ函数实参为2的值(我目前正在做的一个项目)。浮点除法给你带来了一个令人痛苦的舍入误差问题。
另一方面,BigDecimal包含许多用于将表达式计算到任意精度的选项。下面Oracle文档中描述的加、乘、除方法在BigDecimal Java World中“取代”+、*和/:
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方法在这些方面很重要。
如果你正在处理计算问题,那么你应该如何计算以及你应该使用什么样的精度是有规律的。如果你失败了,你就是在做违法的事情。 唯一真正的原因是十进制大小写的位表示不精确。正如巴兹尔所说,例子是最好的解释。为了补充他的例子,下面是发生的事情:
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
推荐文章
- 在流中使用Java 8 foreach循环移动到下一项
- 访问限制:'Application'类型不是API(必需库rt.jar的限制)
- 用Java计算两个日期之间的天数
- 如何配置slf4j-simple
- 在Jar文件中运行类
- 带参数的可运行?
- 我如何得到一个字符串的前n个字符而不检查大小或出界?
- 我可以在Java中设置enum起始值吗?
- Java中的回调函数
- c#和Java中的泛型有什么不同?和模板在c++ ?
- 在Java中,流相对于循环的优势是什么?
- Jersey在未找到InjectionManagerFactory时停止工作
- 在Java流是peek真的只是调试?
- Recyclerview不调用onCreateViewHolder
- 如何舍入一个双到最近的Int在迅速?