Незначительные различия в двойных вычислениях между прогонами - PullRequest
1 голос
/ 26 марта 2012

Другой разработчик дал мне алгоритм, который возвращает последовательность строк, содержащих строковые двойные числа. Я строю модульные тесты на основе этих выходных данных. Около 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

Я знаю, что двойные вычисления могут быть неточными, но я никогда не слышал, чтобы они были вариантами. Автор алгоритма уверен, что алгоритм является детерминированным. Способ, которым удваивается значение toStringed:

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

Я немного затрудняюсь объяснить, как этот вариант возможен. Есть идеи?

Ответы [ 2 ]

3 голосов
/ 26 марта 2012

Я полагаю, что, основываясь только на суммировании, которое вы делаете, это может быть вызвано тем, что двойное сложение не является достаточно коммутативным или ассоциативным - вы получите разные ошибки округления, если вы добавите удвоения в несколько ином заказ.

Просто добавьте небольшой эпсилон для своих юнит-тестов.

0 голосов
/ 26 марта 2012
I am at a bit of a loss explain how this variation is possible.

До тех пор, пока не будет единого языка архитектуры / ОС / языка программирования CPU, чтобы "управлять ими всеми", подобные проблемы будут происходить. Если хотите, вы можете попытаться найти какой-нибудь способ получить числа, чтобы связать 100% с миллионным десятичным знаком, но я думаю, что это пустая трата времени и, вероятно, не будет длиться долго.

Any ideas?

Выберите точность и провалите разницу, только если ваше число не соответствует этой точности. Нет необходимости рассчитывать числа с точностью до 10 знаков после запятой, если вы заботитесь (или можете измерить) только до 2-го числа.

Например, у вас есть это ...

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