浮点误差的确定性如何?我知道浮点计算存在准确性问题,并且有很多问题可以解释原因。我的问题是,如果我两次运行相同的计算,是否可以始终依赖它来产生相同的结果?哪些因素可能会影响到这一点?我有一个简单的物理模拟,想录制会话以便重播。如果可以依赖计算,那么我只需要记录初始状态加上任何用户输入,我应该总是能够准确地重现最终状态。如果计算不准确,开始时的错误会对模拟结束产生巨大影响。我目前在Silverlight工作,但很想知道这个问题是否可以得到一般性的回答。更新:最初的答案表明是的,但显然这并不完全清楚,如对所选答案的评论中所述。看来我将不得不做一些测试,看看会发生什么。据我了解,只要您处理相同的指令集和编译器,并且您运行的任何处理器都严格遵守相关标准(即IEEE754),您就只能保证获得相同的结果。也就是说,除非您处理的是一个特别混乱的系统,否则运行之间的任何计算偏差都不太可能导致错误行为。我所知道的具体陷阱:1.)某些操作系统允许您以破坏兼容性的方式设置浮点处理器的模式。2.)浮点中间结果通常在寄存器中使用80位精度,但在内存中仅使用64位精度。如果以更改寄存器溢出功能的方式重新编译程序,则与其他版本相比,它可能会返回不同的结果。大多数平台都会为您提供一种方法来强制将所有结果截断为内存精度。3.)标准库函数可能会因版本而异。我认为在gcc3和4中有一些不常见的例子。4.)IEEE本身允许一些二进制表示不同......特别是NaN值,但我不记得细节。简而言之,根据IEEE浮点标准,FP计算是完全确定的,但这并不意味着它们可以在机器、编译器、操作系统等之间完全重现。这些问题的长期答案及其答案可以在关于浮点数的最佳参考,“每个计算机科学家都应该知道的关于浮点运算的知识”,作者是DavidGoldberg。有关更多信息,请跳至IEEE标准部分。简要回答您的要点:最后,如果您对相同的初始输入执行相同的浮点计算序列,那么事情应该是完全可重播的。确切的顺序可能会根据您的编译器/操作系统/标准库而改变,因此您可能会以这种方式遇到一些小错误。通常遇到浮点问题的地方是,如果你有一个数值不稳定的方法,并且你从大致相同但不完全相同的FP输入开始。如果你的方法是稳定的,你应该能够保证一定公差内的重复性。如果您需要更多详细信息,请查看上面链接的Goldberg的FP文章,或获取有关数值分析的介绍性文本。我认为您的困惑在于浮点数的不准确类型。大多数语言都执行IEEE浮点标准。该标准指定了如何使用float/double中的各个位来生成数字。通常,浮点数由四个字节和一个双八位字节组成。两个浮点数之间的数学运算每次都具有相同的值(如标准中所指定)。不准确来自精确。考虑一个int与一个float。两者通常占用相同数量的字节(4)。但是,每个数字可以存储的最大值却大不相同。区别在中间。int可以表示0到大约20亿之间的每个数字。但是,浮动不能。它可以表示0到3.40282347E38之间的20亿个值。但这留下了一堆无法表达的价值观。如果一个数学方程式达到这些值之一,它必须四舍五入到一个可表示的值,因此被认为是“不精确的”。您对不准确的定义可能会有所不同:)。此外,虽然Goldberg是一个很好的参考,但原文也是错误的:IEEE754不可移植。我怎么强调都不为过,因为这个陈述是基于浏览文本的频率。该文档的较新版本包括一个专门讨论此问题的部分:许多程序员可能没有意识到,即使是仅使用IEEE标准规定的数字格式和运算的程序也可以在不同的系统上计算出不同的结果。事实上,该标准的作者打算允许不同的实现实现不同的结果。抱歉,但我不禁认为每个人都没有抓住要点。如果不准确对您所做的事情很重要,那么您应该寻找不同的算法。你说如果计算不准确,一开始的错误会对模拟结束产生巨大影响。我的朋友不是嘲笑。如果由于四舍五入和精度的微小差异而得到截然不同的结果,则很可能所有结果都没有任何有效性。仅仅因为您可以重复结果并不能使它更有效。在任何涉及测量或非整数计算的重要现实问题中,引入微小错误来测试算法的稳定性始终是一个好主意。C++常见问题解答中的这个答案可能对其进行了最好的描述:http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.18不仅不同的体系结构或编译器可能会给你带来麻烦,浮动指向数字在同一个程序中已经表现得很奇怪了。如FAQ所述,如果y==x为真,那仍然意味着cos(y)==cos(x)为假。这是因为x86CPU使用80位来计算值,而该值在内存中存储为64位,因此您最终需要将截断的64位值与完整的80位值进行比较。计算仍然是确定性的,因为运行相同的编译二进制文件每次都会给你相同的结果,但是当你稍微调整源代码、优化标志或使用不同的编译器编译时,所有的赌注都会发生。实际上,我还不错,我可以在32位Linux位上重复使用不同版本的GCC进行简单的浮点数学运算,但是当我切换到64位Linux时,结果就不再一样了。在32位上创建的演示记录不能在64位上运行,反之亦然,但在同一个架构上运行时可以正常工作。由于您的问题被标记为C#,因此值得强调.NET面临的问题:浮点数学不是关联的——也就是说,(a+b)+c不保证等于a+(b+c);不同的编译编译器将以不同方式优化您的代码,这可能涉及重新排序算术运算。在.NET中,CLR的JIT编译器将动态编译您的代码,因此编译取决于运行时计算机上的.NET版本。这意味着当在不同版本的.NETCLR上运行时,不应依赖.NET应用程序来产生相同的浮点计算结果。例如,在您的情况下,如果您记录模拟的初始状态和输入,然后安装更新CLR的服务包,则您的模拟在下次运行时可能无法完全重播。请参阅ShawnHargreaves的博客文章浮点数学是确定性的吗?关于.NET的进一步讨论。嗯。由于OP要求使用C#:C#字节码JIT是确定性的还是在不同的运行之间生成不同的代码?我不知道,但我不相信吉特。我可以想到JIT具有某些服务质量特征并决定花更少的时间进行优化的情况,因为CPU正在其他地方进行大量数据处理(想想背景DVD编码)?这可能会导致细微的差异,这些差异可能会在以后导致巨大的差异。此外,如果JIT本身得到改进(可能作为服务包的一部分),生成的代码肯定会发生变化。80位内部精度问题已经提到了。这不是您问题的完整答案,但这里有一个示例证明C#中的双重计算是不确定的。不知道为什么,看似无关的代码却明显影响了下游双倍计算的结果。在VisualStudio版本12.0.40629.00Update5中创建一个新的WPF应用程序并接受所有默认选项。将MainWindow.xaml.cs的内容替换为以下内容:usingSystem;使用System.Windows;namespaceWpfApplication1{//////MainWindow.xaml的交互逻辑///publicpartialclassMainWindow:Window{publicMainWindow(){InitializeComponent();Content=FooConverter.Convert(新点(950,500),新点(850,500));}}publicstaticclassFooConverter{publicstaticstringConvert(PointcurIPJos,PointoppIJPos){varij="绝缘接头";vardeltaX=oppIJPos.X-curIPJos.X;vardeltaY=oppIJPos.Y-curIPJos.Y;varteta=Math.Atan2(deltaY,deltaX);字符串结果;if(-Math.PI/4将构建配置设置为“发布”并构建,但不要在VisualStudio中运行。双击生成的exe以运行它。请注意窗口显示“底部绝缘接头”。现在在“StringResult”之前添加此行:stringdebug=teta.ToString();重复步骤3和4。注意窗口显示“RightInsulatedConnector”。这种行为在同事的机器上得到了证实。请注意,如果满足以下任何条件,该窗口将始终显示“RightInsulatedJoint”:exe是从VisualStudio中运行的,exe是使用调试配置构建的,或者未选中“首选32位”项目属性。很难弄清楚发生了什么,因为任何观察过程的尝试都会改变结果。很少有FPU符合IEEE(尽管他们声称是)。所以在不同的硬件上运行同一个程序确实会得到不同的结果。结果很可能是在您的软件中使用FPU时应该避免的极端情况。IEEE错误通常在软件中修补,您确定您运行的操作系统包含制造商提供的适当陷阱和补丁吗?在操作系统更新之前或之后做什么?是否删除了所有错误并添加了错误修复?C编译器是否与所有这些同步,C编译器是否生成正确的代码?测试这可能是徒劳的。在产品交付之前您不会发现问题。遵循FP规则1:永远不要使用if(something==something)比较。IMO的第二篇文章是关于ascii到fp或fp到ascii(printf、scanf等)。与硬件相比,准确性和错误问题更多。随着每一代新硬件(密度)的出现,来自太阳的影响变得更加明显。我们在行星表面的SEU上遇到过问题,因此独立于浮点计算,你会遇到问题(很少有供应商需要关心,所以预计更新的硬件会更频繁地崩溃)。通过消耗大量逻辑,fpu可以非常快(单个时钟周期)。不比整数alu慢。不要将它与现代fpus混淆,就像alus一样简单,fpus很昂贵。(alus也消耗更多的乘法和除法逻辑以将其降低到一个时钟周期,但它不会像fpu那样大)。遵循上面的简单规则并进一步研究浮点数,以了解随之而来的缺点和陷阱。您可能需要定期检查无穷大或无穷大。您的问题更有可能在编译器和操作系统中发现,而不是在硬件中发现(通常不仅仅是fp数学)。现在,现代硬件(和软件)在定义上充满了错误,所以只是尝试减少错误,而不是运行软件。以上是C#学习教程:浮点数不准确到底有多确定?如果分享的所有内容对您有用,需要了解更多C#学习教程,希望您多多关注---本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
