大家都知道,0.1加0.1结果为0.2,但是下面程序的运行结果和预想的结果有一些差距,
System.out.println("0.05+0.01 = "+(0.05+0.01));
System.out.println("1.0-0.42 = "+(1.0-0.42));
System.out.println("2.0*3.10 = "+(2.0*3.10));
System.out.println("123.3/100 = "+(123.3/100));
运行结果
0.05+0.01 = 0.060000000000000005
1.0-0.42 = 0.5800000000000001
2.0*3.10 = 6.2
123.3/100 = 1.2329999999999999
从上面的结果可以看出,double类型发生了精度丢失的问题,尤其在进行算术运算的时候更容易发生这样的问题。
为了能够精确的表示,计算浮点数,java提供了BigDecimal类来解决浮点数精度丢失的问题。
现贴出BigDecimal类的一个构造函数供大家参考,可以从中找到浮点数精度丢失的解决办法
解决方法:
相信从上面的文档大家也已经找出了解决方法,
在需要精确的表示两位小数时我们需要把他们转换为BigDecimal对象,然后再进行运算。
另外需要注意
使用BigDecimal(double val)构造函数时仍会存在精度丢失问题,建议使用BigDecimal(String val)这就需要先把double转换为字符串然后在作为BigDecimal(String val)构造函数的参数。转换为BigDecimal对象之后再进行加减乘除操作,这样精度就不会出现问题了。这也是为什么有关金钱数据存储都使用BigDecimal。
如果必须使用double浮点数作为BigDecimal构造器的参数时,不要直接将该double浮点数作为构造器参数创建BigDecimal对象,而是应该通过BigDecimal.valueOf(doubel value)静态方法来创建BigDecimal对象。
BigDecimal类的方法:
BigDecimal类的一些常用方法可以在java1.8API帮助文档里查看;
打开文档->搜索->输入BigDecimal,在右边就可以看到BigDecimal类的所有方法;
下面程序分别使用BigDecimal的基本运算:
package Base3;
import java.math.BigDecimal;
public class BIgDecimalTest {
public static void main(String[] args){
BigDecimal b1 = new BigDecimal("0.05");
BigDecimal b2 = BigDecimal.valueOf(0.05);
BigDecimal b3 = new BigDecimal(0.05);
System.out.println("使用String作为BigDecimal构造器参数:");
System.out.println("0.05+0.01 = "+b1.add(b2));
System.out.println("0.05-0.01 = "+b1.subtract(b2));
System.out.println("0.05*0.01 = "+b1.multiply(b2));
System.out.println("0.05/0.01 = "+b1.divide(b2));
System.out.println("使用double作为BigDecimal构造器参数:");
System.out.println("0.05+0.01 = "+b3.add(b2));
System.out.println("0.05-0.01 = "+b3.subtract(b2));
System.out.println("0.05*0.01 = "+b3.multiply(b2));
System.out.println("0.05/0.01 = "+b3.divide(b2));
}
}
运算结果
使用String作为BigDecimal构造器参数:
0.05+0.01 = 0.10
0.05-0.01 = 0.00
0.05*0.01 = 0.0025
0.05/0.01 = 1
使用double作为BigDecimal构造器参数:
0.05+0.01 = 0.10000000000000000277555756156289135105907917022705078125
0.05-0.01 = 2.77555756156289135105907917022705078125E-18
从上面程序运行结果可以看出BigDecimal进行算术运算的效果,而且可以看出创建BigDecimal对像时,一定要使用String对象作为构造器参数,而不是直接使用double数字。
如果程序中要求对double浮点数进行基本运算,则需要先将double类型数字包装成BigDecimal对象,调用BigDecimal对象的方法执行运算后再转换成double型变量。这是一个比较繁琐的过程,可以考虑以BigDecimal为基础定义一个Arith工具类,该工具类代码如下:
package Base3;
import java.math.BigDecimal;
public class Arith {
private static final int DEF_DIV_SCALE = 10;
private Arith(){}
public static double add(double v1,double v2){
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return b1.add(b2).doubleValue();
}
public static double sub(double v1,double v2){
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return b1.subtract(b2).doubleValue();
}
public static double mul(double v1,double v2){
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return b1.multiply(b2).doubleValue();
}
public static double div(double v1,double v2){
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return b1.divide(b2, DEF_DIV_SCALE, BigDecimal.ROUND_HALF_UP).doubleValue();
}
public static void main(String[] args){
System.out.println("0.05+0.01 = "+Arith.add(0.05, 0.01));
System.out.println("1.0-0.42 = "+Arith.sub(1.0, 0.42));
System.out.println("4.015*100 = "+Arith.mul(4.015, 100));
System.out.println("123.3/100 = "+Arith.div(123.3, 100));
}
}
运行结果
0.05+0.01 = 0.06
1.0-0.42 = 0.58
4.015*100 = 401.5
123.3/100 = 1.233