赞
踩
一般,我们会用float和double来存储有小数的数据,可能还会用两个浮点型数据进行计算,在某些情况下,float和double会出现精度损失,导致存储的数据或者计算结果出现误差。
public class Test {
public static void main(String[] args) {
double a = 0.11;
double b = 2.32;
System.out.println(a + b);
System.out.println(0.11 + 2.32);
float c = 0.11f;
float d = 2.32f;
System.out.println(c + d);
}
}
执行结果如下:
2.4299999999999997
2.4299999999999997
2.4299998
这个结果并不是我们预期的2.43。很明显,精度损失了,虽然仅比原来小了0.00000000000003,但是如果是我们银行卡里的金额,那可就出大问题了。
经过测试,还发现以下两种情况:
2.13
2.13
2.1299999
1.1300000000000001
1.1300000000000001
1.13
气人啊!
计算机用0和1来表示数据,并没有小数,浮点型数据采用IEEE754标准,浮点型数据如何存储可以参考这篇文章。
《Effective Java》中写道:
float 和 double 类型主要用于科学计算和工程计算。它们执行二进制浮点运算,该算法经过精心设
计,能够在很大范围内快速提供精确的近似值。但是,它们不能提供准确的结果,也不应该在需要精确
结果的地方使用。float 和 double 类型特别不适合进行货币计算,因为不可能将 0.1(或 10 的任意负次
幂)精确地表示为 float 或 double。
所有的编程语言中应该都有这个问题,而不仅仅是Java。
那么,如何解决这个问题呢?
用java.math.BigDecimal,并且根据《阿里Java开发规范》,应该使用BigDecimal(“0.01”)这种方式创建对象,而不能用BigDecimal(0.01)这种方式。
12.【强制】禁止使用构造方法 BigDecimal(double)的方式把 double 值转化为 BigDecimal 对象。
说明:BigDecimal(double)存在精度损失风险,在精确计算或值比较的场景中可能会导致业务逻辑异常。
如:BigDecimal g = new BigDecimal(0.1F); 实际的存储值为:0.10000000149
正例:优先推荐入参为 String 的构造方法,或使用 BigDecimal 的 valueOf 方法,此方法内部其实执行了
Double 的 toString,而 Double 的 toString 按 double 的实际能表达的精度对尾数进行了截断。
BigDecimal recommend1 = new BigDecimal(“0.1”);
BigDecimal recommend2 = BigDecimal.valueOf(0.1)
另外,在数据库中,也应该使用decimal,而不是float和double。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。