Il existe de nombreux défis techniques qui rendent la reproductibilité bit à bit exacte des résultats de calcul extrêmement difficile à réaliser.
Au niveau logiciel, les modifications apportées au code ou à l'une des bibliothèques utilisées par le code peuvent évidemment entraîner des résultats différents. Vous seriez surpris du nombre de bibliothèques de support qui peuvent finir par être liées dans un code scientifique typique.
À un niveau inférieur, la recompilation du code ou des bibliothèques utilisées par le code avec un nouveau compilateur ou avec différentes optimisations de compilateur activées peut également provoquer des problèmes. L'une des raisons est que diverses opérations dans le code peuvent être effectuées dans un ordre différent lorsque le code est recompilé. Étant donné que l'addition en virgule flottante n'est pas associative (a + b) + c <> a + (b + c), cela peut donner des résultats différents.
OK, que se passe-t-il si nous préservons l'ensemble de l'environnement logiciel (système d'exploitation, bibliothèques et code compilé) en (par exemple) en le gravant sur un CD-Rom amorçable qui exécutera le code. Maintenant, pouvons-nous être sûrs que nous obtiendrons les mêmes résultats si nous exécutons ce code sur un autre ordinateur?
Étonnamment, certains codes varient en fait l'ordre des calculs en fonction des aspects du modèle de processeur particulier sur lequel ils s'exécutent. Par exemple, les bibliothèques d'algèbre linéaire optimisées cassent généralement les multiplications matricielles pour travailler sur des blocs qui tiendront dans le cache. Lorsque Intel publie un nouveau microprocesseur avec un cache plus grand, le code peut ajuster dynamiquement la taille du bloc, ce qui entraîne une arithmétique qui est effectuée dans un ordre différent et donne des résultats différents. D'autres codes ajustent dynamiquement l'ordre des calculs en fonction de la quantité de mémoire disponible - si vous exécutez le code sur un ordinateur avec plus de mémoire, ce qui pourrait bien faire effectuer l'arithmétique dans un ordre différent et donner ainsi des résultats différents.
Les choses deviennent incroyablement plus compliquées lorsque vous ajoutez du code multithread, car l'historique d'exécution exact des différents threads est souvent non déterministe et cela peut à nouveau entraîner des opérations arithmétiques dans un ordre différent d'une exécution à l'autre.
Dans la pratique, on ne peut vraiment espérer que des résultats similaires d'une machine à l'autre, jusqu'aux tolérances de précision des algorithmes utilisés. Par exemple, si j'ai un problème de recherche de racine et que j'utilise la bissection pour obtenir une racine à + -1.0e-10, je serais heureux tant que différentes machines produisent des réponses qui correspondent à cette tolérance.