java浮点数的精确计算

首先来个小栗子:

public class Calculate{
 public static void main(String[] args){
 double x=2;
 double y=1.1;
 double z=x-y;
 System.out.println(z);
 }
}

编译,运行,控制台打印结果为0.8999999999999999。

是不是有点不对?

口算一下,2-1.1=0.9。

虽说0.8999999999999999与0.9十分接近,但是为什么会出现这样的问题?该如何解决?

问题的原因就在于浮点数(主要是小数部分)在二进制中的表示机制。这个机制用文字描述是这样的:

将小数部分乘以2,取其整数部分(非0即1)作为二进制表示的第一位。重复此步骤,得到全部的二进制表示。直到小数部分为0时停止。

看上去没有问题,但是如果碰到类似下面的情况:

0.4*2=0.8取0

0.8*2=1.6取1

0.6*2=1.2取1

0.2*2=0.4取0

到这里就能看出来了,这是一个循环。也就是说,用有限的二进制码无法无法表示这个小数,存在误差,这个误差导致基本数据类型的浮点数运算出现误差。

上面强调了一下基本数据类型,而为了解决问题,需要对此进行规避,可以采用BigDecimal类来实现精确的浮点数计算。

把前面的栗子处理一下:

import java.math.BigDecimal;
public class Calculate{
 public static void main(String[] args){
 BigDecimal x=new BigDecimal("2");
 BigDecimal y=new BigDecimal("1.1");
 BigDecimal z=x.subtract(y);
 System.out.println(z);
 }
}

得到正解0.9。

这里简单介绍一下BigDecimal类的四个方法,分别用来将两个BigDecimal类的实例对象进行加减乘除的运算。

加法:add()

减法:subtract()

乘法:multiplay()

除法:divide()

需要注意的是,在创建实例对象,调用BigDecimal类的构造方法时,一定要传入数字字符串参数,如果直接使用浮点数或该类型的变量作为参数,那么构造方法接收的是经过二进制存储的浮点数,就不再精确。


阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页