2012-03-26 3 views
1

Ein anderer Entwickler hat mir einen Algorithmus gegeben, der eine Reihe von Strings zurückgibt, die doppelte Strings enthalten. Ich baue Komponententests gegen diese String-Ausgänge. Ungefähr 80% der Zeit, die ich meine Unit-Tests laufen sie alle bestanden. In den anderen 20% der Zeit treten geringfügige Abweichungen im doppelten Teil der zurückgegebenen Saiten auf. Zum Beispiel:Geringfügige Variation bei Doppelberechnungen zwischen Läufen

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 

Ich weiß, dass doppelte Berechnungen ungenau sein können, aber ich habe nie davon gehört, dass sie Varianten sind. Der Autor des Algorithmus versichert mir, dass der Algo deterministisch ist. Die Art und Weise, dass das Doppel zuStringed ist, ist:

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

Ich bin bei ein wenig Verlust erklären, wie diese Variation möglich ist. Irgendwelche Ideen?

+3

Können Sie die String-Eingänge einzuloggen, um die gleichen Eingaben zwischen den Läufen erhalten zu gewährleisten, * in die gleiche Reihenfolge *? –

+0

Um zu sehen, wie viel Variation eine andere Reihenfolge machen kann http://vanillajava.blogspot.co.uk/2012/03/differences-results-summing-double.html Ich füge 1001 Werte in zufälliger Reihenfolge hinzu und erzeuge über 1000 verschiedene Summen. ;) –

Antwort

3

Nur basierend auf der Summierung, die Sie tun, vermute ich, dass dies durch das Problem verursacht werden kann, dass doppelte Addition nicht vollständig kommutativ oder assoziativ ist - Sie erhalten verschiedene Rundungsfehler, wenn Sie doppelt in ein wenig hinzufügen andere Reihenfolge.

Fügen Sie einfach ein kleines Epsilon für Ihre Komponententests, im Grunde.

+0

+1. Interessanter Einblick. – aioobe

+0

Das war das Problem. Entwickler hat über eine HashMap iteriert, die die Reihenfolge festlegte, in der Doppelgänger multipliziert wurden. Auf TreeMap umgestellt und die Berechnung ist jedes Mal reproduzierbar. – Dejas

+0

'LinkedHashMap' könnte auch funktionieren; Es ist Hash-basiert, aber die Iterationsreihenfolge ist konsistent. –

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

Bis es eine CPU Architektur/os/Programmiersprache gibt, um "alle zu beherrschen", werden solche Probleme passieren. Sie können versuchen, einen Weg zu finden, um die Zahlen 100% auf die millionste Dezimalstelle zu setzen, wenn Sie möchten, aber ich denke, das ist Zeitverschwendung und wird wahrscheinlich nicht dauern.

Wählen Sie eine Genauigkeit und nur einen Unterschied, wenn Ihre Zahl innerhalb dieser Genauigkeit fehlschlägt. Es ist nicht notwendig, Zahlen auf die 10 Dezimalstellen zu berechnen, wenn Sie nur bis zum 2. interessiert sind (oder in der Lage sind zu messen).

Zum Beispiel haben Sie diese ...

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? 

Mit anderen Worten ...

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

IEE 754 * ist * ein Standard, der "alle Regeln" beherrscht, wenn es um Fließkomma geht. –

Verwandte Themen