zoukankan      html  css  js  c++  java
  • 编程规范之浮点数的比较

    一、问题

    项目在 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。

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

    static 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 
    }

    大体是这个意思把。以上是c语法,也不甚很严谨,没测试。

    浮点数的比较方法,百度上一大堆,大家可以搜一下。这里就不详细讲解了。

  • 相关阅读:
    HUST 1372 marshmallow
    HUST 1371 Emergency relief
    CodeForces 629D Babaei and Birthday Cake
    CodeForces 629C Famil Door and Brackets
    ZOJ 3872 Beauty of Array
    ZOJ 3870 Team Formation
    HDU 5631 Rikka with Graph
    HDU 5630 Rikka with Chess
    CodeForces 626D Jerry's Protest
    【POJ 1964】 City Game
  • 原文地址:https://www.cnblogs.com/senline/p/foat_number_compare.html
Copyright © 2011-2022 走看看