我知道浮点计算存在准确性问题,并且有很多问题可以解释原因.我的问题是,如果我运行两次相同的计算,我是否可以始终依赖它来产生相同的结果?哪些因素可能会影响这个?
计算之间的时间?
CPU的当前状态?
不同的硬件?
语言/平台/操作系统?
太阳耀斑?
我有一个简单的物理模拟,并希望记录会话,以便他们可以重播.如果可以依赖计算,那么我只需要记录初始状态加上任何用户输入,我应该始终能够完全重现最终状态.如果计算不准确,那么在开始时错误可能会在模拟结束时产生巨大影响.
我目前在Silverlight工作,但有兴趣知道这个问题是否可以回答一般.
更新: 初始答案表明是,但显然这并不完全清楚,如所选答案的评论中所述.看起来我将不得不做一些测试,看看会发生什么.
根据我的理解,只有您处理相同的指令集和编译器,并且您运行的任何处理器严格遵守相关标准(即IEEE754),您才能保证相同的结果.也就是说,除非你正在处理一个特别混乱的系统,否则运行之间的任何计算偏差都不可能导致错误的行为.
我所知道的特定陷阱:
1.)某些操作系统允许您以破坏兼容性的方式设置浮点处理器的模式.
2.)浮点中间结果通常在寄存器中使用80位精度,但在内存中只有64位.如果以更改寄存器溢出函数的方式重新编译程序,则与其他版本相比,它可能返回不同的结果.大多数平台都会为您提供一种方法来强制将所有结果截断为内存精度.
3.)标准库函数可能在版本之间发生变化.我认为在gcc 3 vs 4中有一些不常见的例子.
4.)IEEE本身允许一些二进制表示不同......特别是NaN值,但我不记得细节.
简而言之,根据IEEE浮点标准,FP计算完全是确定性的,但这并不意味着它们可以在机器,编译器,操作系统等之间完全重现.
这些问题的长期答案可以在浮点数的最佳参考中找到,David Goldberg的"每个计算机科学家应该知道的关于浮点算术的内容".有关详细信息,请跳至IEEE标准部分.
简要回答一下你的要点:
计算和CPU状态之间的时间与此无关.
硬件会影响事物(例如,某些GPU不符合IEEE浮点).
语言,平台和操作系统也会影响事物.为了更好地描述这一点,请参阅Jason Watkins的回答.如果您使用Java,请查看Kahan 对Java浮点不足的咆哮.
太阳耀斑可能很重要,希望不经常发生.我不会太担心,因为如果它们确实重要,那么其他一切也都搞砸了.我会把它放在与担心EMP相同的类别中.
最后,如果您在相同的初始输入上执行相同的浮点计算序列,那么事情应该可以完全重放.确切的顺序可能会根据您的编译器/ os /标准库而改变,因此您可能会以这种方式获得一些小错误.
如果你有一个数值不稳定的方法并且你开始使用大致相同但不完全相同的FP输入,那么你通常遇到浮点问题.如果您的方法稳定,您应该能够在一定的容差范围内保证重现性.如果您想了解更多细节,请查看上面链接的Goldberg的FP文章,或者获取有关数值分析的介绍文本.
我认为你的困惑在于浮点周围的不准确类型.大多数语言都实现了IEEE浮点标准.该标准规定了如何使用float/double中的各个位来生成数字.通常,浮点数由四个字节和一个双八字节组成.
两个浮点数之间的数学运算每次都具有相同的值(在标准中指定).
精度不准确.考虑一个int与一个浮点数.两者通常占用相同的字节数(4).然而,每个数字可以存储的最大值是完全不同的.
int:大约20亿
float:3.40282347E38(相当大)
区别在于中间.int,可以表示0到大约20亿之间的每个数字.然而,Float不能.它可以代表0到3.40282347E38之间的20亿个值.但这留下了一系列无法表达的价值观.如果数学等式达到这些值中的一个,则必须将其四舍五入为可表示的值,因此被认为是"不准确的".您对不准确的定义可能会有所不同:).