您的位置:首页 > 编程语言 > Java开发

Java 浮点数计算问题

2016-11-19 22:49 274 查看

问题

double a = (3.3-2.4)/0.1;

System.out.println(a);

你可能认为结果很简单,不就是9嘛,是事实上,结果为:8.999999998,为什么呢?

分析

为什么浮点数会丢失精度?

十进制数的二进制表示可能不够精确

浮点数或是双精度浮点数无法精确表示的情况并不少见。浮点数值没办法用十进制来精确表示的原因要归咎于CPU表示浮点数的方法。这样的话您就可能会牺牲一些精度,有些浮点数运算也会引入误差。以上面提到的情况为例,2.4的二进制表示并非就是精确的2.4。反而最为接近的二进制表示是 2.3999999999999999。原因在于浮点数由两部分组成:指数和尾数。浮点数的值实际上是由一个特定的数学公式计算得到的。您所遇到的精度损失会在任何操作系统和编程环境中遇到。

解决方式

四舍五入

我们的第一个反应是做四舍五入。Math类中的round方法不能设置保留几位小数,我们只能象这样(保留两位):

public double round(double value){
return Math.round(value*100)/100.0;
}


非常不幸,上面的代码并不能正常工作,给这个方法传入4.015它将返回4.01而不是4.02,如我们在上面看到的

4.015*100=401.49999999999994

因此如果我们要做到精确的四舍五入,不能利用简单类型做任何运算

java.text.DecimalFormat也不能解决这个问题:

System.out.println(new java.text.DecimalFormat(“0.00”).format(4.025));

输出是4.02

BigDecimal

在《Effective Java》这本书中也提到这个原则,float和double只能用来做科学计算或者是工程计算,在商业计算中我们要用java.math.BigDecimal。BigDecimal一共有4个够造方法,我们不关心用BigInteger来够造的那两个,那么还有两个,它们是:

BigDecimal(double val)

Translates a double into a BigDecimal.

BigDecimal(String val)

Translates the String repre sentation of a BigDecimal into a BigDecimal.

上面的API简要描述相当的明确,而且通常情况下,上面的那一个使用起来要方便一些。我们可能想都不想就用上了,会有什么问题呢?等到出了问题的时候,才发现上面哪个够造方法的详细说明中有这么一段:

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不可!

BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
System.out.println(b1.add(b2).doubleValue());//加
System.out.println(b1.subtract(b2).doubleValue());//减
System.out.println(b1.multiply(b2).doubleValue());//乘
System.out.println(b1.divide(b2).doubleValue());//除


建议

float和double只能用来做科学计算或者是工程计算,在商业计算中我们要用java.math.BigDecimal
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java float