关于Java中float和double的精度损失
Java当中的float和double类型的主要设计目标是为了简单的科学计算和工程计算。他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的。然而,它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合。正式场合应该使用BigDecimal。
float
我们来看看这个例子:
float base = 0.0F;
for (int i = 0;i<100;i++){
base+=0.01;
}
System.out.println(base);//0.99999934
我们使用float把一百个0.01相加,结果却出人意料,
且每次执行结果都一样。如果用float的包装类Float,也还是一样的结果,因为包装类其实还是封装了基本类型。
double
我们来看看double的表现:
double base = 0.0;
for (int i = 0;i<100;i++){
base+=0.01;
}
System.out.println(base);//1.0000000000000007
使用double计算的结果是:1.0000000000000007
如果使用double或float来表示用户卡里的余额,在经过多次的转账、消费、存取款后,难免余额会有一定损失,几分钱可能我们并不在意,但是假如是一个商城系统,上亿的订单,如果每笔订单都损失1分钱,emm
那么money一般而言还是存成BigDecimal比较好。
同时构建BigDecimal对象的时候使用带String参数的构造方法,否则可能会给你带来意想不到的惊喜😂
BigDecimal
我们试试用double构建BigDecimal:
double base = 0.0;
double increment = 0.01;
BigDecimal bd = new BigDecimal(base);
for (int i = 0;i<100;i++){
bd = bd.add(new BigDecimal(increment));
}
System.out.println(bd);//1.00000000000000002081668171172168513294309377670288085937500
结果是:1.00000000000000002081668171172168513294309377670288085937500,因为double本身就不精确,所以构建的BigDecimal 也失去了其精确性。
强烈推荐使用带String参数的构造方法:
BigDecimal bd = new BigDecimal("0.0");
for (int i = 0;i<100;i++){
bd = bd.add(new BigDecimal("0.01"));
}
System.out.println(bd);//1.00