c – 什么可能导致确定性过程产生浮点错误

已经阅读过这个 question,我有理由确定使用具有相同输入的浮点算术的给定进程(在相同的硬件上,使用相同的编译器编译)应该是确定性的.我正在研究一个不成立的案例,并试图确定可能导致这种情况的原因.

我已经编译了一个可执行文件,我正在为它提供完全相同的数据,在一台机器上运行(非多线程)但是我得到的错误约为3.814697265625e-06,经过仔细的谷歌搜索,我发现实际上等于1 / 4 ^ 9 = 1/2 ^ 18 = 1/262144.这非常接近32位浮点数的精度等级(根据维基百科大约7位数)

我怀疑它与已应用于代码的优化有关.我正在使用intel C编译器,并且已经将浮动点推测变为快速而不是安全或严格.这会使浮点过程不确定吗?是否存在可能导致此行为的其他优化措施?

编辑:根据pax的建议,我重新编译了浮点投机的代码转向安全,我现在得到稳定的结果.这让我可以澄清这个问题 – 浮点推测实际上做了什么以及如何在应用于完全相同的输入时,导致相同的二进制(即一次编译,多次运行)产生不同的结果?

@Ben我正在使用英特尔(R)C 11.0.061 [IA-32]进行编译,而我正在运行英特尔四核处理器.

解决方法

几乎在任何有快速模式和安全模式的情况下,你都会找到某种权衡.否则一切都将以快速安全模式运行:-).

并且,如果您使用相同的输入得到不同的结果,那么无论您认为它有多少,您的过程都不是确定性的(尽管有经验证据).

我会说你的解释是最有可能的.将其置于安全模式,看看非确定性是否消失.这肯定会告诉你.

至于是否还有其他优化,如果您使用相同的编译器/链接器和相同的选项编译相同的硬件,它应该生成相同的代码.除了快速模式之外,我看不到任何其他可能性(或者由于宇宙射线而在内存中发生位腐烂,但这种可能性很小).

更新后:

英特尔有一份文件here,解释了他们在安全模式下不允许做的一些事情,包括但不限于:

>重新关联:(a b)c – > a(b c).
>零折叠:x 0 – > x,x * 0 – > 0.
>倒数乘法:a / b – >一个*(1 / B).

虽然您声明这些操作是编译时定义的,但英特尔芯片非常聪明.他们可以重新排序指令,以便在多cpu设置中保持管道完整,因此,除非代码明确禁止此类行为,否则事情可能会在运行时(而不是编译时)发生变化,以使事情保持全速运行.

这个(简要地)在该链接文档的第15页上讨论了矢量化(“问题:在同一处理器上的相同数据上重新运行相同二进制文件的不同结果”).

我的建议是决定你是否需要原始的咕噜声或结果的完全再现性,然后根据它选择模式.

相关文章

本程序的编译和运行环境如下(如果有运行方面的问题欢迎在评...
水了一学期的院选修,万万没想到期末考试还有比较硬核的编程...
补充一下,先前文章末尾给出的下载链接的完整代码含有部分C&...
思路如标题所说采用模N取余法,难点是这个除法过程如何实现。...
本篇博客有更新!!!更新后效果图如下: 文章末尾的完整代码...
刚开始学习模块化程序设计时,估计大家都被形参和实参搞迷糊...