我有一个用 C 编写的相当大的模型(约 5000 行)。它是一个串行程序,在任何地方都没有随机数生成。它使用 FFTW 库来处理使用 FFT 的函数——我不知道 FFTW 实现的细节,但我认为其中的函数也是确定性的(如果我出错了,请纠正我)。
我无法理解的问题是,在同一台机器(相同的编译器,相同的库)上运行相同的结果我得到了微小的差异。
我使用双精度变量,并将结果输出到变量value
中,例如,我发出:
fprintf(outFID, "%.15e\n", value);
或
fwrite(&value, 1, sizeof(double), outFID);
而且我会不断得到差异,例如:
2.07843469652206 4 e-16 vs. 2.07843469652206 3 e-16
我花了很多时间试图弄清楚为什么会这样。我最初以为我的一个内存芯片坏了,我已经订购并更换了它们,但无济于事。随后我还尝试在同事的 Linux 机器上运行我的代码,我得到了相同性质的差异。
这可能是什么原因造成的?现在这是一个小问题,但我想知道它是否是“冰山一角”(一个严重的问题)。
我想我会在这里而不是 StackOverflow 发帖,以防使用数值模型的人可能遇到这个问题。如果有人能阐明这一点,我将不胜感激。
评论跟进:
Christian Clason 和 Vikram:首先,感谢您关注我的问题。您链接到的文章表明:1.舍入误差限制了准确性,2.不同的代码(例如引入看似无害的打印语句)可能会影响机器epsilon的结果。我应该澄清一下,我不是在比较效果fwrite
和fprintf
功能。我正在使用一个或另一个。特别是,两次运行都使用相同的可执行文件。我只是说明无论我使用fprintf
OR都会出现问题fwrite
。
所以代码路径(和可执行文件)是一样的,硬件也是一样的。在所有这些外部因素保持不变的情况下,从根本上说,随机性从何而来?我怀疑位翻转的发生是由于内存故障没有正确保留位,这就是我更换内存芯片的原因,但这似乎不是问题,我验证了,你指出了。我的程序在一次运行中输出了数千个这样的双精度数字,并且总是有少数随机位翻转。
跟进 Christian Clason 的第一条评论:为什么在机器精度内与 0 相同?双精度的最小正数是 2.22e-308,所以它不应该等于 0 吗?我的程序输出了 10^-16 范围内的数千个值(范围从 1e-15 到 8e-17),我们在研究项目中看到了有意义的变化,所以我希望我们没有在看荒谬的数字。