本文共 3713 字,大约阅读时间需要 12 分钟。
public static void main( String[] args ) { System.out.println(0.05+0.01); System.out.println(1.0-0.42); System.out.println(4.015*100); System.out.println(123.3/100); } //输出 0.060000000000000005 0.5800000000000001 401.49999999999994 1.2329999999999999
事实上,浮点数并不适合用于精确计算,而适合进行科学计算。这里有一个小知识:既然float和double型用来表示带有小数点的数,那为什么我们不称 它们为“小数”或者“实数”,要叫浮点数呢?因为这些数都以科学计数法的形式存储。当一个数如50.534,转换成科学计数法的形式为5.053e1,它 的小数点移动到了一个新的位置(即浮动了)。可见,浮点数本来就是用于科学计算的,用来进行精确计算实在太不合适了。
public static void main(String[] args) { BigDecimal aa = new BigDecimal(0.31); BigDecimal bb = new BigDecimal(0.2); BigDecimal cc = new BigDecimal(0.11); System.out.println(aa.subtract(bb).doubleValue()); //转换成double System.out.println(aa.subtract(bb)); System.out.println(cc.compareTo(aa.subtract(bb))); } //输出 0.10999999999999999 0.109999999999999986677323704498121514916419982910156250 1
BigDecimal其中一个构造函数以双精度浮点数作为输入,然而得到的结果仍然不是我们想要的。要小心使用 BigDecimal(double)构造函数,因为如果不了解它,会在计算过程中产生舍入误差。请使用基于整数或 String 的构造函数。
在《Effective Java》这本书中也提到这个原则,float和double只能用来做科学计算或者是工程计算,在商业计算中我们要用java.math.BigDecimal。使用BigDecimal并且一定要用String来够造。
BigDecimal用哪个构造函数?
BigDecimal(double val)
BigDecimal(String val)
上面的API简要描述相当的明确,而且通常情况下,上面的那一个使用起来要方便一些。我们可能想都不想就用上了,会有什么问题呢?等到出了问题的时候,才发现参数是double的构造方法的详细说明中有这么一段:Note: the results of this constructor can be somewhat unpredictable. One might assume that new BigDecimal(.1) is exactly equal to .1, but it is actually equal to .1000000000000000055511151231257827021181583404541015625. This is so because .1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the long value that is being passed in to the constructor is not exactly equal to .1, appearances nonwithstanding.
The (String) constructor, on the other hand, is perfectly predictable: new BigDecimal(".1") is exactly equal to .1, as one would expect. Therefore, it is generally recommended that the (String) constructor be used in preference to this one.
原来我们如果需要精确计算,非要用String来够造BigDecimal不可!
public static void main(String[] args) { BigDecimal aa = new BigDecimal("0.31"); BigDecimal bb = new BigDecimal("0.2"); BigDecimal cc = new BigDecimal("0.11"); System.out.println(aa.subtract(bb).doubleValue()); System.out.println(aa.subtract(bb)); System.out.println(cc.compareTo(aa.subtract(bb))); } //输出 0.11 0.11 0
如浮点类型一样,BigDecimal 也有一些令人奇怪的行为。尤其在使用 equals() 方法来检测数值之间是否相等时要小心。 equals() 方法认为,两个表示同一个数但换算值不同(例如, 100.00 和 100.000 )的 BigDecimal 值是不相等的。然而, compareTo() 方法会认为这两个数是相等的,所以在从数值上比较两个 BigDecimal 值时,应该使用 compareTo() 而不是 equals() 。
另外还有一些情形,任意精度的小数运算仍不能表示精确结果。例如,1 除以 9 会产生无限循环的小数 .111111… 。出于这个原因,在进行除法运算时,BigDecimal 可以让您显式地控制舍入。 movePointLeft() 方法支持 10 的幂次方的精确除法。
public static void main(String[] args) { BigDecimal aa = new BigDecimal("0.31"); BigDecimal bb = new BigDecimal("0.2"); BigDecimal cc = new BigDecimal("0.11"); int r = cc.compareTo(aa.subtract(bb)); if(r==0) //等于 if(r==1) //大于 if(r==-1) //小于 }
转载地址:http://orhpi.baihongyu.com/