编程规范之浮点数的比较

一、问题

项目在组 UAT,客户报了一个错误,说在提交一个单子的时候,系统报“主表总金额与明细汇总总金额不相等”,提交失败。

编程规范之浮点数的比较

二、分析原因

开发上死活查不出原因,也不能再现错误,用用户的账号提交报错的单子也没问题,提交成功。说用户是不是看花眼了等等。

我帮他分析原因。

我:这个检查是前台校验,还是后台校验

开发:后台校验

我:是不是提交时,没有保存数据,修改前确实不相等,导致检查不通过

开发:不会,单据投的金额是根据明细行自动汇总计算的,并且提交前强制保存数据。

我让测试试图再现这个问题。

果然,测试竟然再现了这个问题,从界面上看,金额事项等的。

我:你把校验逻辑再检查一下

开发:检查了好几遍了,没问题

我:把校验逻辑发给我

开发:

double pBckpje = 0.0;
double pSumje = 0.0;

//取主表总金额
//-----省略
//取明细汇总金额
//-----省略

if (CommonUtils.round(pBckpje, 2) != CommonUtils.round(pSumje, 2)) {
            throw new Exception("主表总金额与明细汇总总金额不相等");
} 

浮点数这样比较???

因为这段代码是为老程序员写的,我一点没有怀疑是浮点数比较的问题。所以我不大相信,因为这里用到了一个工具类的round方法,也许里边有什么玄机。

我:把这个round 代码贴出来:

开发:

public static double round(double amt, int scale) {
        BigDecimal bigDecimal = new BigDecimal(String.valueOf(amt));
        return bigDecimal.setScale(scale,BigDecimal.ROUND_HALF_UP).doubleValue();
}

看到这里我有点上火了。

这个方法用bigdecimal 做了 round,然后有转换成了double返回,对后边的比较一点好处没有。

三、如何比较浮点数

大家都知道,在二级制世界中,浮点数是不精确的,因此直接用 <>=!=比较浮点数大小是很危险的,而且结果也是不确定的。

不考虑精度来比较浮点数大小是耍流氓。我之前的做法是基于精度对浮点数进行比较,比如,精度为2,如果 abs(d1-d2)<0.01,就说明 d1=d2。否则就是 d1>d2。

可以在工具类中,实现一个浮点数比较的方法:

int floatCompare( double d1, double d2, int scale ){
   if (Math.Abs( d1 - d2 ) < 1/10^scale )
       return 0 ; //d1=d2
   else if ( d1 - d2 >= 1/10^scale )return 1 ; // d1>d2 
   return -1 ; //d1<d2 
}

大体是这个意思把。java 语法不熟悉,类语言写的,也不甚很严谨,没测试。

百度上一大堆,大家可以搜一下。这里就不详细讲解了。

上一篇:CSS2D效果变形


下一篇:ichartjs一分钟快速入门教程