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语法,也不甚很严谨,没测试。

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

  • 相关阅读:
    Tinyhttpd
    Fiddler教程(Web调试工具)
    windows消息值全部定义,从消息值得到消息名称(系统消息定义从0到1023,从1024开始就是WM_USER,但是中间有325个WM_undefined消息,估计是备用,另外各控件都有一些reserved消息,也是为了备用)LostSpeed
    生意经:凡是现今比较会赚钱或是规模比较大的软件公司大都属于开发"消费型软件"的公司(而且登广告,应该定低价进行销售)
    Folly: Facebook Open-source Library Readme.md 和 Overview.md(感觉包含的东西并不多,还是Boost更有用)
    DefaultFilesMiddleware中间件如何显示默认页面
    Linux模块编程框架
    编程一小时
    DirectoryBrowserMiddleware中间件如何呈现目录结构
    gRpc NET Core
  • 原文地址:https://www.cnblogs.com/senline/p/foat_number_compare.html
Copyright © 2011-2022 走看看