有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在两次运行之间的双重计算中略有变化

另一个开发人员给了我一个算法,它返回一系列包含字符串化双精度的字符串。我正在针对这些字符串输出构建单元测试。大约80%的时间我运行我的单元测试,它们都通过了。其他20%的时间在返回字符串的双精度部分发生轻微变化。例如:

Expected: ((B,D),(C,A)); : 0.05766153477579324
Found:    ((B,D),(C,A)); : 0.05766153477579325

Expected: (B,(C,(A,D))); : 0.0017518688483315935
Found     (B,(C,(A,D))); : 0.001751868848331593

我知道双重计算可能不精确,但我从来没有听说过它们是不同的。算法作者向我保证算法是确定性的。双精度旋转的方式是:

    for(Tree gt: geneTrees){
        double prob = probList.next();
        total += prob;
        result.append("\n" + gt.toString() + " : " + prob);
    }

我有点不知道如何解释这种变化是可能的。有什么想法吗


共 (2) 个答案

  1. # 1 楼答案

    仅仅根据你正在做的求和,我怀疑这可能是由于二重加法不是完全交换的或结合的,如果你以稍微不同的顺序加二重,你会得到不同的舍入误差

    基本上,只需为单元测试添加一个小ε

  2. # 2 楼答案

    I am at a bit of a loss explain how this variation is possible.
    

    除非有一种cpu架构/操作系统/编程语言来“统领一切”,否则这样的问题就会发生。如果你愿意的话,你可以试着找到一些方法,把数字100%固定到小数点后百万位,但我认为这是浪费时间,而且很可能不会持续

    Any ideas?
    

    选择一个精度,只有当你的数字在该精度范围内失败时,才失败一个差异。如果你只关心(或能够测量)到第二位的数字,就不需要计算到小数点后10位

    例如,你有这个

    Expected: ((B,D),(C,A)); : 0.05766153477579324
    Found:    ((B,D),(C,A)); : 0.05766153477579325
                                                 ^
                                                 |
                                                 |
                                   If this was a 9...would it change the behavior
                                   of whoever is using your calculation?
    

    换句话说

    Double expected = 0.05......
    Double actual = Double.parseDouble(valueFromFile);
    
    // Instead of doing this....
    if(!expected.equals(actual)) {
      // fail test..
    }
    
    // Do this (only substitute .0001 with whatever you think an acceptable number is
    // based off of the precision possible of the measurement of your input)....
    if(Math.Abs(expected - actual) > .0001) {
       // fail test...
    }