我知道无论操作系统,编程语言如何,都存在浮点不准确。然而,我发现这个例子没有不准确之处。这怎么可能呢?我认为将string转换为double是需要计算的,所以应该有浮点不准确!
import java.math.*;
class NoErrorBigDecimal {
public static void main(String[] args)
{
BigDecimal e1=new BigDecimal("1.6");
BigDecimal e2=new BigDecimal("0.1");
System.out.println("result of add : "+e1.add(e2));
System.out.println("result of multiplication : "+e1.multiply(e2));
}
}
如何使BigDecimal不产生浮点误差?
答案是不能。
浮点误差(如你所说)是计算机中实际数字表示的基础。
对于BigDecimal
命题的反例是1/3的值不能用单个BigDecimal
(或float
或double
)精确地表示。
-
可以用3进制浮点数精确表示,但这是不切实际的。
-
它可以通过(假设的)任意精度的有理数表示精确地表示,但是没有标准的Java SE类实现它。
另一方面,如果你把自己限制在可以精确地表示为有限十进制浮点字符串的数字(如"1.6"
和"0.1"
),那么BigDecimal
可以表示所有这些数字…精确。
我认为将string转换为double是需要计算的,所以应该有浮点不准确!
实际上,这并不意味着会有不准确的地方。它取决于具体的计算、具体的表示和(通常)实际值。例如:
我可以(平凡地)实现计算
1 / 2
,并且(如果硬件工作)保证结果将准确地表示为float
或double
。将
String
形式的十进制数转换为BigDecimal
形式不涉及任何有失去精度风险的计算。(由标准库实现,并假设有O(N)
可用内存…(其中N
为输入字符串长度)
好的,所以这里的推论是Double提供比BigDecimal更高的精度,或者提供"无浮点误差"。你说每种编程语言都必须对舍入做出让步,这是正确的。Java也不例外
相对于其他数字类型,BigDecimal通过许多构造函数(例如BigDecimal(long val, MathContext mc))和舍入模式(例如ROUND_UP)为程序员提供了对缩放和舍入的更大控制[参见Java 7 API- http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html]。这就是在处理货币时首选BigDecimal类型的原因。