目录
项目场景
银行风控系统,累积某个卡一天的累积金额=0.3时触发一个规则。如我今天发生了两笔交易,第一笔0.1完成后数据库保存了0.1,第二笔0.2发生后我们在做规则命中完成后需要将数据库中的0.1加上当前这一笔0.2的金额进行判断是否满足规则
问题描述
最近的项目中发现一个问题,在进行double数据类型的金额字段进行计算的时候发现结果不能符合预期,如double a=0.1;double b=0.2; double c=a+b; 得到的c并不是0.3而是0.30000000000000004,也就是说0.1+0.2不等于0.3
public static void main(String[] args) {
double a=0.1;
double b =0.2;
double c = a+b;
System.out.println(c);
}
原因分析
1. 二进制表示:计算机使用二进制来表示浮点数,而不是十进制。在二进制系统中,一些十进制小数无法被准确地表示为有限的二进制小数。例如,0.1(十进制)在二进制中是无限循环的小数。当你将其转换为二进制表示时,会出现舍入误差,例如:0.1(十进制)=0.0001100110011001(二进制) 2. 有限精度:浮点数的表示是有限的,无法精确地表示所有的实数。例如,double类型使用64位表示,其中一部分用于表示符号、指数和小数部分。由于位数的限制,某些小数无法精确表示,因此会出现舍入误差。
注: 这个问题和是什么语言以及什么程序无关,计算机底层运算都是这样的
解决方案
具体的解决方法有两个:
1. 直接将double数值进行四舍五入后在进行运算,我在项目中使用了这种方式
2. 不要使用浮点类型,全部用int因为如果是单笔交易的金额的话int的大小足够用了,然后直接进行加减运算
public static double rounding(double value) {
BigDecimal result = new BigDecimal(String.valueOf(value)).setScale(2,
BigDecimal.ROUND_HALF_UP);
return result.doubleValue();
}
总结
项目中需要用到浮点类型的数值计算需要特别注意这一点,而且需要基于业务来考虑应该使用什么数据类型,保留几位小数等问题。