一为什么使用BigDecimal??
由与java中的浮点型float 和double类型对数字的计算不是精确表达,为了解决这个问题,Java 中提供了大数字(超过16位有效位)的操作类,即 java.math.BigInteger 和 java.math.BigDecimal 类,用于高精度的数值计算。
BigInteger : 针对大整数的处理类
BigDecimal: 针对大的浮点数的处理类,其实现用到了BigInteger 类。
与float 和double类型比较:
由于float和double 不精确,所以,适合用来做科学计算和工程计算,而在商业计算中,必须使用BigDecimal 和BigInteger, 他们支持任何精度的定点数,可以用来精确计算货币值。
float 和double 类型的数值进行加减乘除的时候会出现跟想的结果不一样的情况,代码如下:
public static void main(String[] args)
{
System.out.println(0.2 + 0.1);
System.out.println(0.3 - 0.1);
System.out.println(0.2 * 0.1);
System.out.println(0.3 / 0.1);
}
//输出的结果
0.30000000000000004
0.19999999999999998
0.020000000000000004
2.9999999999999996
二 BigDecimal 的构造方法
(1)BigDecimal BigDecimal(double d); //不允许使用,创建的浮点数仍然是不精确的值。
示例: BigDecimal bNum=new BigDecimal(0.1);
(2)BigDecimal BigDecimal(String s); //常用,推荐使用
//方法一
BigDecimal bNum=new BigDecimal("0.1");
// 方法二
BigDecimal bNum=new BigDecimal(Double.toString(0.1));
(3)static BigDecimal valueOf(double d); //常用,推荐使用 ,直接将浮点数传进去。
示例:BigDecimal bNum=BigDecimal.valueOf(0.1);
三 类成员方法:加减乘除 ,看源码
public BigDecimal add(BigDecimal augend):加
public BigDecimal subtract(BigDecimal subtrahend):减
public BigDecimal multiply(BigDecimal multiplicand):乘
public BigDecimal divide(BigDecimal divisor):除
四 浮点数比较大小
对于BigDecimal 类的大数,可以调用compareTo() 方法,如:
public static boolean equalTo(BigDecimal b1, BigDecimal b2) {
if(b1 == null || b2 == null) {
return false;
}
return 0 == b1.compareTo(b2);
}
对于double 和float类型的数值比较是否相等的时候的时候,不能直接用 == 或 != 进行比较。
判断两个浮点数是否相等可以用两个差的绝对值是否大于0 来进行判断。
double a=0.1;
double b=0.11;
boolean isEqual(double a,double b)
{
if(Math.abs(a-b)<=0)
{
System.out.println("相等");
return true;
}
}
不同比较是否相等的方法测试:
public class Test{
public static void main(String[] args){
isEqualOfFloat(10.222222225f, 10.222222229f);
}
public static void isEqualOfFloat(float a, float b){
System.out.println(a==b); // 超出精度范围 true
System.out.println(Math.abs(a-b)>0); //输出 false
System.out.println( Math.abs(a-b)<0.00000001 ); // true
System.out.println(a<b); //false;
System.out.println(a>b); //false
}
}
思考:为什么浮点数的大小不能用等号比较大小??? (与计算机保存浮点数的方式是有关系的,无法精确保存)
即使在精度相同的情况下,比较也可能会出问题。因为在运算过程中会将内存(或高速缓存)中的值加载到CPU浮点寄存器(80 bit扩展精度)中,然后再进入CPU浮点计算单元进行计算,计算结果写回浮点寄存器,然后写回内存(或高速缓存)。从内存到浮点寄存器,浮点数的精度会扩展,从浮点寄存器到内存,浮点数的精度会降低(精度扩展通常没问题,但如果精度降低了,很可能值会发生变化,出现截断),而浮点运算的结果由于下面还要使用所以暂时保存在浮点寄存器中留待下次使用(没有及时写回内存,这是一种优化策略),从而导致数据并不是内存中和内存中的数据比较而是浮点寄存器中的值和内存中的值进行比较,而无论内存中是float类型还是double类型,其精度和浮点寄存器精度都不相同,从而导致比较结果是不相等。
链接:https://www.cnblogs.com/xiehongfeng100/p/4851201.html
五 总结
(1)商业计算使用BigDecimal。
(2)尽量使用参数类型为String的构造函数。
(3) BigDecimal都是不可变的(immutable)的,在进行每一步运算时,都会产生一个新的对象,所以在做加减乘除运算时千万要保存操作后的值。
(4)我们往往容易忽略JDK底层的一些实现细节,导致出现错误,需要多加注意。