Java Double 与 BigDecimal?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3413448/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Double vs. BigDecimal?
提问by Truong Ha
I have to calculate some floating point variables and my colleague suggest me to use BigDecimal
instead of double
since it will be more precise. But I want to know what it is and how to make most out of BigDecimal
?
我必须计算一些浮点变量,我的同事建议我使用BigDecimal
而不是double
因为它会更精确。但我想知道它是什么以及如何充分利用它BigDecimal
?
采纳答案by extraneon
A BigDecimal
is an exact way of representing numbers. A Double
has a certain precision. Working with doubles of various magnitudes (say d1=1000.0
and d2=0.001
) could result in the 0.001
being dropped alltogether when summing as the difference in magnitude is so large. With BigDecimal
this would not happen.
ABigDecimal
是表示数字的精确方式。ADouble
有一定的精度。使用不同量级的双精度数(例如d1=1000.0
和d2=0.001
)可能会导致在0.001
求和时完全丢弃,因为量级差异如此之大。有了BigDecimal
这个就不会发生了。
The disadvantage of BigDecimal
is that it's slower, and it's a bit more difficult to program algorithms that way (due to +
-
*
and /
not being overloaded).
缺点BigDecimal
是速度较慢,并且以这种方式编写算法有点困难(由于+
-
*
而/
不是过载)。
If you are dealing with money, or precision is a must, use BigDecimal
. Otherwise Doubles
tend to be good enough.
如果您正在处理金钱,或者必须精确,请使用BigDecimal
. 否则Doubles
往往足够好。
I do recommend reading the javadocof BigDecimal
as they do explain things better than I do here :)
我确实建议您阅读javadoc,BigDecimal
因为它们确实比我在这里解释的更好:)
回答by Meros
There are two main differences from double:
与 double 有两个主要区别:
- Arbitrary precision, similarly to BigInteger they can contain number of arbitrary precision and size
- Base 10 instead of Base 2, a BigDecimal is n*10^scale where n is an arbitrary large signed integer and scale can be thought of as the number of digits to move the decimal point left or right
- 任意精度,类似于 BigInteger 它们可以包含任意精度和大小的数量
- 基数 10 而不是基数 2,BigDecimal 是 n*10^scale,其中 n 是任意大的有符号整数,并且可以将比例视为向左或向右移动小数点的位数
The reason you should use BigDecimal for monetary calculations is not that it can represent any number, but that it can represent all numbers that can be represented in decimal notion and that include virtually all numbers in the monetary world (you never transfer 1/3 $ to someone).
您应该使用 BigDecimal 进行货币计算的原因不是它可以表示任何数字,而是它可以表示可以用十进制表示的所有数字,并且几乎包括货币世界中的所有数字(您永远不会转移 1/3 $给某人)。
回答by fishermanhat
BigDecimal is Oracle's arbitrary-precision numerical library. BigDecimal is part of the Java language and is useful for a variety of applications ranging from the financial to the scientific (that's where sort of am).
BigDecimal 是 Oracle 的任意精度数值库。BigDecimal 是 Java 语言的一部分,可用于从金融到科学的各种应用程序(这就是 am)。
There's nothing wrong with using doubles for certain calculations. Suppose, however, you wanted to calculate Math.Pi * Math.Pi / 6, that is, the value of the Riemann Zeta Function for a real argument of two (a project I'm currently working on). Floating-point division presents you with a painful problem of rounding error.
对某些计算使用双打并没有错。但是,假设您想计算 Math.Pi * Math.Pi / 6,即黎曼 Zeta 函数的值,用于实参数为 2(我目前正在进行的一个项目)。浮点除法给您带来了一个痛苦的舍入错误问题。
BigDecimal, on the other hand, includes many options for calculating expressions to arbitrary precision. The add, multiply, and divide methods as described in the Oracle documentation below "take the place" of +, *, and / in BigDecimal Java World:
另一方面,BigDecimal 包括许多用于将表达式计算为任意精度的选项。下面的 Oracle 文档中描述的加法、乘法和除法方法“代替”了 BigDecimal Java World 中的 +、* 和 /:
http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html
http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html
The compareTo method is especially useful in while and for loops.
compareTo 方法在 while 和 for 循环中特别有用。
Be careful, however, in your use of constructors for BigDecimal. The string constructor is very useful in many cases. For instance, the code
但是,在使用 BigDecimal 的构造函数时要小心。字符串构造函数在许多情况下非常有用。例如,代码
BigDecimal onethird = new BigDecimal("0.33333333333");
BigDecimal onethird = new BigDecimal("0.33333333333");
utilizes a string representation of 1/3 to represent that infinitely-repeating number to a specified degree of accuracy. The round-off error is most likely somewhere so deep inside the JVM that the round-off errors won't disturb most of your practical calculations. I have, from personal experience, seen round-off creep up, however. The setScale method is important in these regards, as can be seen from the Oracle documentation.
使用 1/3 的字符串表示来表示无限重复的数字到指定的准确度。舍入误差很可能在 JVM 深处的某个地方,以至于舍入误差不会干扰您的大部分实际计算。然而,根据个人经验,我看到四舍五入逐渐上升。setScale 方法在这些方面很重要,从 Oracle 文档中可以看出。
回答by Basil
My English is not good so I'll just write a simple example here.
我的英语不好,所以我就在这里写一个简单的例子。
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);
Program output:
程序输出:
0.009999999999999998
0.01
Somebody still want to use double? ;)
有人还想用double吗?;)
回答by Olivier Jacot-Descombes
If you write down a fractional value like 1 / 7
as decimal value you get
如果你写下一个小数值,比如1 / 7
十进制值,你会得到
1/7 = 0.142857142857142857142857142857142857142857...
with an infinite sequence of 142857
. Since you can only write a finite number of digits you will inevitably introduce a rounding (or truncation) error.
的无限序列142857
。由于您只能写入有限数量的数字,因此您将不可避免地引入舍入(或截断)错误。
Numbers like 1/10
or 1/100
expressed as binary numbers with a fractional part also have an infinite number of digits after the decimal point:
像1/10
或1/100
表示为带小数部分的二进制数的数字在小数点后也有无限位数:
1/10 = binary 0.0001100110011001100110011001100110...
Doubles
store values as binary and therefore might introduce an error solely by converting a decimal number to a binary number, without even doing any arithmetic.
Doubles
将值存储为二进制,因此仅通过将十进制数转换为二进制数可能会引入错误,甚至无需进行任何算术运算。
Decimal numbers (like BigDecimal
), on the other hand, store each decimal digit as is. This means that a decimal type is not more precise than a binary floating point or fixed point type in a general sense (i.e. it cannot store 1/7
without loss of precision), but it is more accurate for numbers that have a finite number of decimal digits as is often the case for money calculations.
BigDecimal
另一方面,十进制数(如)按原样存储每个十进制数字。这意味着十进制类型并不比一般意义上的二进制浮点或定点类型更精确(即它不能在1/7
不损失精度的情况下存储),但对于具有有限十进制数字的数字更准确,如货币计算通常是这种情况。
Java's BigDecimal
has the additional advantage that it can have an arbitrary (but finite) number of digits on both sides of the decimal point, limited only by the available memory.
Java 的BigDecimal
另一个优点是它可以在小数点两侧具有任意(但有限)数量的数字,仅受可用内存的限制。
回答by jfajunior
If you are dealing with calculation, there are laws on how you should calculate and what precision you should use. If you fail that you will be doing something illegal. The only real reason is that the bit representation of decimal cases are not precise. As Basil simply put, an example is the best explanation. Just to complement his example, here's what happens:
如果您正在处理计算,则有关于您应该如何计算以及应该使用什么精度的法律。如果你失败了,你将做一些违法的事情。唯一真正的原因是十进制情况的位表示不精确。正如巴兹尔简单地说,一个例子是最好的解释。只是为了补充他的例子,下面是发生的事情:
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)));
}
Output:
输出:
Double: 0,3 - 0,2 = 0.09999999999999998
Float: 0,3 - 0,2 = 0.10000001
BigDec: 0,3 - 0,2 = 0.1
Also we have that:
我们还有:
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)));
}
Gives us the output:
给我们输出:
Double: 10 / 3 = 3.3333333333333335
Float: 10 / 3 = 3.3333333
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion
But:
但:
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)));
}
Has the output:
有输出:
BigDec: 10 / 3 = 3.3333