Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/144.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 什么会导致确定性进程生成浮点错误_C++_Floating Point_Intel_Deterministic - Fatal编程技术网

C++ 什么会导致确定性进程生成浮点错误

C++ 什么会导致确定性进程生成浮点错误,c++,floating-point,intel,deterministic,C++,Floating Point,Intel,Deterministic,读过这篇文章后,我可以合理地确定,使用相同输入(在相同硬件上,使用相同编译器编译)的浮点算术的给定进程应该是确定性的。我在看一个不符合事实的案例,并试图确定是什么导致了这一结果 我已经编译了一个可执行文件,并且在一台机器上运行(非多线程),给它提供了完全相同的数据,但是我得到了大约3.814697265625e-06的错误,在仔细搜索之后,我发现它实际上等于1/4^9=1/2^18=1/262144。这非常接近32位浮点数的精度级别(根据wikipedia,大约7位) 我怀疑这与应用于代码的优化

读过这篇文章后,我可以合理地确定,使用相同输入(在相同硬件上,使用相同编译器编译)的浮点算术的给定进程应该是确定性的。我在看一个不符合事实的案例,并试图确定是什么导致了这一结果

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

我怀疑这与应用于代码的优化有关。我使用英特尔C++编译器,并将浮点猜测转换为快速而非安全或严格。这会使浮点进程不确定吗?是否存在其他可能导致这种行为的优化等

编辑:根据Pax的建议,我重新编译了代码,将浮点推测转换为安全的,现在我得到了稳定的结果。这使我能够澄清这个问题——浮点推测实际上做了什么?当应用于完全相同的输入时,它如何导致相同的二进制文件(即一次编译、多次运行)生成不同的结果


本编译我用英特尔(R)C++ +0.061(IA32),我在英特尔四核处理器上运行。p> 在几乎任何有快速模式和安全模式的情况下,您都会找到某种权衡。否则一切都将在快速安全模式下运行:-)

而且,如果你用相同的输入得到不同的结果,你的过程是不确定的,不管你多么相信它(尽管有经验证据)

我认为你的解释是最有可能的。把它放在安全模式,看看非决定论是否消失了。这肯定会告诉你的

至于是否还有其他优化,如果您使用相同的编译器/链接器在相同的硬件上进行编译,并且这些工具具有相同的选项,那么它应该生成相同的代码。除了快速模式(或者由于宇宙射线导致内存中有点腐烂,但这不太可能),我看不到其他任何可能性

更新后:

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

  • 重新关联:
    (a+b)+c->a+(b+c)
  • 零折叠:
    x+0->x,x*0->0
  • 倒数乘法:
    a/b->a*(1/b)
虽然您声明这些操作是编译时定义的,但Intel芯片非常聪明。他们可以对指令进行重新排序,以便在多CPU设置中保持管道完整,因此,除非代码明确禁止此类行为,否则在运行时(而不是编译时)可能会发生变化,以保持高速运行

关于矢量化的链接文档的第15页(简要)介绍了这一点(“问题:不同的结果在同一处理器上的相同数据上重新运行相同的二进制文件”)


我的建议是,决定您是否需要原始的咕噜声或结果的完全可复制性,然后在此基础上选择模式。

如果您的程序是并行的,就像它可能在四核上运行一样,那么它很可能是不确定的

假设有4个处理器将浮点值添加到同一内存位置。那你可能会

(((InitialValue+P1fp)+P2fp)+P3fp)+P4fp

或任何其他可能的订单

见鬼,你甚至可能会

 InitialValue+(P2fp+P3fp)+(P1fp+P4fp)
如果编译器足够好

不幸的是,浮点加法不是交换的或结合的。由于舍入、溢出和下溢,实数运算是,浮点运算不是

因此,并行FP计算通常是非确定性的。“经常”,因为程序看起来像

  on each processor
    while( there is work to do ) {
       get work
       calculate result
       add to total 
    }
将是不确定的,因为每次所需的时间可能会有很大的差异-您无法预测操作的顺序。(如果线程相互作用,情况会更糟。)

但并不总是这样,因为有一些类型的并行编程是确定性的

当然,许多关心决定论的人所做的是用整数或定点来避免这个问题。我特别喜欢超级累加器,512、1024或2048位的数字,浮点数可以添加到这些数字中,而不会出现舍入错误


对于单线程应用程序:编译器可能会重新排列代码。不同的汇编可能给出不同的答案。但任何特定的二进制都应该是确定性的

除非。。。您使用的是动态语言。它执行优化,对FP计算进行重新排序,并随时间变化


或者除非。。。很长的路要走:安腾有一些特性,比如ALAT,这使得即使是单线程编码也无法确定。您不太可能受到这些影响。

什么处理器和什么编译器。。如果你已经知道是哪个标志导致了它,为什么不检查一下编译器文档?@Tal-我很难从文档中找到任何东西(它只是说fast启用fps,而safe/strict禁用fps)。据我所知,fps允许对操作进行重新排序(ac+bc=>c*(a+b)),但这是编译时优化,生成的二进制文件应该仍然是确定性的,我真的很想知道为什么不是。当您在单个内核上运行可执行文件时,不确定性会消失吗?谢谢您的解释和参考资料。您链接的文档中确实指出,此问题(全局堆栈地址和对齐方式可能因当前运行的进程之外的事件而更改)已解决
  on each processor
    while( there is work to do ) {
       get work
       calculate result
       add to total 
    }