Java 两次运行之间的重复计算略有变化

Java 两次运行之间的重复计算略有变化,java,unit-testing,double,Java,Unit Testing,Double,另一个开发人员给了我一个算法,它返回一系列包含字符串化双精度的字符串。我正在针对这些字符串输出构建单元测试。大约80%的时间我运行我的单元测试,它们都通过了。其他20%的时间在返回字符串的双精度部分发生轻微变化。例如: Expected: ((B,D),(C,A)); : 0.05766153477579324 Found: ((B,D),(C,A)); : 0.05766153477579325 Expected: (B,(C,(A,D))); : 0.0017518688483315

另一个开发人员给了我一个算法,它返回一系列包含字符串化双精度的字符串。我正在针对这些字符串输出构建单元测试。大约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);
    }

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

仅根据您正在进行的求和,我怀疑这可能是由于二重加法不是完全可交换或关联的问题造成的——如果您以稍微不同的顺序添加二重,您将得到不同的舍入错误

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

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

您是否可以记录字符串输入,以确保在两次运行之间以相同的顺序获得相同的输入?为了了解不同的顺序可以产生多大的变化,我以随机顺序添加1001个值,并生成1000多个不同的和IEE754是一个标准,当涉及到浮点运算时,它“规定了所有的规则”。这就是问题所在。开发人员正在迭代一个HashMap,该HashMap确定了double的相乘顺序。切换到TreeMap,每次计算都是可重复的。
LinkedHashMap
也可以工作;它是基于散列的,但其迭代顺序是一致的。