一般来说,一提到Java里面的商业计算,我们都知道不能用float和double,
因为这两种基本浮点类型容易引起精度丢失。
例如下程序:
package bigDecumal;
public class DoubleTest {
public static void main(String[] args) {
System.out.println("0.06+0.01: "+(0.06+0.01));
System.out.println("1.0-0.42: "+(1.0-0.42));
System.out.println("1.015*100: "+(1.015*100));
System.out.println("123.3/100: "+(123.3/100));
}
}
输出结果是:
0.06+0.01: 0.06999999999999999
1.0-0.42: 0.5800000000000001
1.015*100: 101.49999999999999
123.3/100: 1.2329999999999999
为能精确表示,计算浮点数,Java提供了BigDecimal类,该类提供了大量的构造器用来创建BigDecimal对象。
1.不推荐使用BigDecimal(double val)构造器,因为使用该构造器时有一定的不可预知性,当程序使用new BigDecimal(0.1)创建一个BigDecimal对象时,它的值并不是0.1,实际上是一个近似0.1的数。
2.建议优先使用基于String的构造器,使用BigDecimal(String val)构造器时可以预知的,写入new BigDecimal("0.1")将创建一个恰好等于0.1的BigDecimal。
3.如果必须使用double浮点数作为BigDecimal构造器的参数时,不要使用double作为参数,而应该通过BigDecimal.valueOf(double value)静态方法来创建对象。
例如:
package bigDecumal;
import java.math.BigDecimal;
public class BigDecimalTest {
public static void main(String[] args){
BigDecimal f1=new BigDecimal("0.06");
BigDecimal f2=BigDecimal.valueOf(0.01);
BigDecimal f3=new BigDecimal(0.06);
System.out.println(f1);
System.out.println(f2);
System.out.println(f3);
System.out.println("使用String作为BigDeacimal构造器参数:");
System.out.println("0.06+0.01: "+f1.add(f2));
System.out.println("0.06-0.01: "+f1.subtract(f2));
System.out.println("0.06*0.01: "+f1.multiply(f2));
System.out.println("0.06/0.01: "+f1.divide(f2));
System.out.println("使用double作为BigDeacimal构造器参数:");
System.out.println("0.06+0.01: "+f3.add(f2));
System.out.println("0.06-0.01: "+f3.subtract(f2));
System.out.println("0.06*0.01: "+f3.multiply(f2));
System.out.println("0.06/0.01: "+f3.divide(f2));
}
}
输出结果为:
0.06
0.01
0.059999999999999997779553950749686919152736663818359375
使用String作为BigDeacimal构造器参数:
0.06+0.01: 0.07
0.06-0.01: 0.05
0.06*0.01: 0.0006
0.06/0.01: 6
使用double作为BigDeacimal构造器参数:
0.06+0.01: 0.069999999999999997779553950749686919152736663818359375
0.06-0.01: 0.049999999999999997779553950749686919152736663818359375
0.06*0.01: 0.00059999999999999997779553950749686919152736663818359375
0.06/0.01: 5.9999999999999997779553950749686919152736663818359375
如果程序中要求使用double浮点数进行加减乘除基本运算,则需要先将double类型数值包装成BigDecimal对象,调用DigDecimal对象的方法执行运算后再将结果转成double型变量。
例如:
package bigDecumal;
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();
}
// 提供精确的乘法运算,当除不尽时精确到小数点以后10位的数字四舍五入
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.06+0.01: "+Arith.add(0.06, 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.06+0.01: 0.07
1.0-0.42: 0.58
4.015*100: 401.5
123.3/100: 1.233