转载

double、Double与BigDecimal

在电商与金融场景中,对数据的敏感程度较高,一旦出现了精度的问题,如果涉及到金钱,精度问题造成了误差,误差就会演变成错误,会造成一定的经济损失,这是大家都不希望见到的

所以今天,来学习一下,如何正确的使用double、Double与BigDecimal

double与Doubl e

double是一种基本数据类型,创建引用,存放在栈中,8字节 ,不可为NULL

Double是一个类,创建对象,存放在堆中,可以为NULL

Double是对double类型的封装(也可以说是包装类),内置很多方法可以实现String到double的转换,以及获取各种double类型的属性值(MAX_VALUE,SIZE等)

double可以自动拆箱和自动装箱,把double类型数据转换成Double,那么这个数据就可以使用Double中的所有方法

另外,由于Double是包装类型(可为NULL),在接口中使用的时候,也只能使用包装类型,不能使用基本数据类型,例如:ThreadLocal< Double >、List< Double >、Map< Double ,Object>等

double在使用中,还会有一些隐藏的坑

1.计算时出现不准确的问题

System.out.println(12.3 + 45.6);
// 57.900000000000006
System.out.println(1.14 / 100);
// 0.011399999999999999

double的小数部分容易出现使用二进制无法准确表示

如十进制的0.1,0.2,0.3,0.4 都不能准确表示成二进制

可参考: https://blog.csdn.net/Lixuanshengchao/article/details/82049191

2.判断double是否相等需要注意

在使用 == 判断两个double是否相等时,如果double超过了16位,会出现问题

16位,不相等

double a = 1.1234567890123451;
double b = 1.1234567890123452;
System.out.println(a == b); // false

17位,相等

double a = 1.12345678901234561;
double b = 1.12345678901234567;
System.out.println(a == b); // true

如果在使用场景中,对数据的敏感程度不高,可以容忍精度损失的情况,例如:计算占比,百分比等情况,本身对数据的结果是未知的,且数据不敏感, 推荐使用double,节省了时间和空间

Double与BigDecimal

与Double相同,BigDecimal也是一个类, 创建对象,存放在堆中

上文我们说过,double超过了16位就会有一些精度损失的问题,那么BigDecimal就是用来对超过16位有效位的数进行精确的运算

因为BigDecimal是一个类,所以在运算中无法直接进行 + – x ÷ 等算术运算符的的操作,而要调用对应的方法

同样在BigDecimal在使用中也要注意一些问题

1.new BigDecimal(double) 与  BigDecimal.valueOf(double)

先来举个例子

BigDecimal bd1 = BigDecimal.valueOf(12.3);
// 12.3
BigDecimal bd2 = new BigDecimal(12.3);
// 12.300000000000000710542735760100185871124267578125

通过上面的例子可以看出,new BigDecimal的方式,可能不是你想要的结果,这种问题,早在 在源码中  BigDecimal(double) 构造函数的注释中就有说明(感兴趣的请查看源码),说明如下:

1)参数类型为double的构造方法的结果有一定的不可预知性

有人可能认为在Java中写入newBigDecimal(0.1)所创建的BigDecimal正好等于 0.1(非标度值 1,其标度为 1),但是它实际上等于

0.1000000000000000055511151231257827021181583404541015625,这是因为0.1无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)

这样,传入到构造方法的值不会正好等于  0.1(虽然表面上等于该值)

2)String 构造方法是完全可预知的:写入 newBigDecimal(“0.1”) 将创建一个 BigDecimal,它正好等于预期的 0.1,因此,比较而言, 通常 建议优先使用String构造方法

3)当double必须用作BigDecimal的源时,请注意,此构造方法提供了一个准确转换;它不提供与以下操作相同的结果:先使用Double.toString(double)方法,然后使用BigDecimal(String)构造方法,将double转换为String。要

获取该结果,请使用 static valueOf(double) 方法

另外,BigDecimal.valueOf() 是静态工厂类,永远优先于构造函数, 所以,在使用的时候, 推荐使用 BigDecimal.valueOf(xxx)

dd

原文  http://www.louisvv.com/archives/2514.html
正文到此结束
Loading...