Есть много технических проблем, которые делают точную побитовую воспроизводимость результатов вычислений чрезвычайно труднодостижимой.
На уровне программного обеспечения изменения в коде или любой из библиотек, используемых в коде, очевидно, могут привести к различным результатам. Вы будете удивлены количеством вспомогательных библиотек, которые в конечном итоге могут быть связаны в типичный научный код.
На более низком уровне перекомпиляция любого кода или любой библиотеки, используемой кодом, с новым компилятором или с другими включенными оптимизациями компилятора также может вызвать проблемы. Одна из причин заключается в том, что различные операции в коде могут выполняться в другом порядке при перекомпиляции кода. Поскольку сложение с плавающей точкой не является ассоциативным (a + b) + c <> a + (b + c), это может дать разные результаты.
Хорошо, а что если мы сохраним всю программную среду (ОС, библиотеки и скомпилированный код), (например) записав ее на загрузочный CD-Rom, который будет выполнять код. Теперь мы можем быть уверены, что получим те же результаты, если запустим этот код на другом компьютере?
Удивительно, но некоторые коды фактически меняют порядок вычислений в зависимости от аспектов конкретной модели процессора, на которой они работают. Например, оптимизированные библиотеки линейной алгебры обычно разбивают умножения матриц для работы с блоками, которые помещаются в кэш. Когда Intel выпускает новый микропроцессор с большим кешем, код может динамически корректировать размер блока, что приводит к арифметике, которая выполняется в другом порядке и дает разные результаты. Другие коды динамически корректируют порядок вычислений в зависимости от объема доступной памяти - если вы запускаете код на компьютере с большим объемом памяти, что может привести к тому, что арифметика будет выполнена в другом порядке и, таким образом, даст другие результаты.
Ситуация становится намного сложнее, когда вы добавляете многопоточный код, поскольку точная история выполнения различных потоков часто недетерминирована, и это может снова привести к тому, что арифметические операции будут выполняться в другом порядке от одного цикла к другому.
На практике самое большее, на что вы действительно можете надеяться - это результаты, которые схожи от одной машины к другой с точностью до допусков точности используемых алгоритмов. например, если у меня есть проблема с поиском корня и я использую разделение пополам, чтобы получить корень в пределах + -1.0e-10, то я должен быть счастлив, если разные машины выдают ответы, согласующиеся в пределах этого допуска.