Answers:
如您所提到的,它允许不保留严格的IEEE合规性的优化。
一个例子是这样的:
x = x*x*x*x*x*x*x*x;
至
x *= x;
x *= x;
x *= x;
由于浮点算术不是关联的,因此由于四舍五入,运算的顺序和因式分解会影响结果。因此,不能在严格的FP行为下完成此优化。
我实际上没有检查过GCC是否确实进行了这种特殊的优化。但是想法是一样的。
double
,但因应用而异)。要注意的一件事是,快速数学优化不一定会添加“更多”的四舍五入。不符合IEEE标准的唯一原因是,答案与所写内容有所不同(尽管略有不同)。
x
小于10,则Mystical示例中的错误将降低10 ^ -10左右。但是,如果x = 10e20
错误可能是数百万。
-fassociative-math
其中包含的内容,-funsafe-math-optimizations
而其中又启用了-ffast-math
GCC为什么不优化a*a*a*a*a*a
为(a*a*a)*(a*a*a)
?
-ffast-math
除了打破严格的IEEE规范外,还可以做更多的事情。
首先,当然会破坏严格的IEEE规范,例如允许将指令重新排序为在数学上相同(理想情况下)但在浮点上不完全相同的东西。
其次,它禁用了errno
单指令数学函数之后的设置,这意味着避免写入线程局部变量(这在某些体系结构上对于那些函数可能造成100%的差异)。
第三,它假设所有数学都是有限的,这意味着不会对NaN(或零)进行检查,否则会产生不利影响。仅仅假设这不会发生。
第四,它可以进行倒数逼近除法和倒数平方根的。
此外,它禁用有符号零(即使目标支持,代码也假定不存在有符号零)和舍入数学,这可以在编译时进行常量折叠。
最后,它生成的代码假定不会因信号发送/陷阱数学运算而发生硬件中断(也就是说,如果无法在目标体系结构上禁用这些中断,并且因此而发生,则不会进行处理)。
-ffast-math
设置-fno-math-errno,-funsafe-math优化,-ffinite-math-only,-fno-rounding-math,-fno-signaling -nans和-fcx-limit-range。此选项将定义预处理程序宏FAST_MATH。 “以及glibc中的某些内容,例如(math.h
靠近math_errhandling)” 默认情况下,所有功能均支持errno和异常处理。在gcc的快速数学模式下,如果定义了内联函数,则可能不正确。 ”
-ffast-math
允许编译器偷工减料并兑现某些承诺(如前所述),这通常并不危险,对大多数人来说也不是问题。对于大多数人来说,是一样的,只是速度更快。但是,如果您的代码假设并依赖于这些承诺,那么您的代码可能会表现出与预期不同的行为。通常,这意味着该程序在大多数情况下似乎都可以正常运行,但是某些结果可能是“意外”的(例如,在物理模拟中,两个对象可能无法正确碰撞)。
-O2
通常会进行“每一个”法律优化,但那些以速度为代价的法律除外。-O3
还可以进行以速度为代价的优化。它仍然保持100%正确性。-ffast-math
试图通过允许“轻微不正确”的行为来加快数学运算的速度,这种行为通常是无害的,但是被标准的措辞认为是不正确的。如果您的代码在两个编译器上的速度确实有很大不同(不仅仅是1-2%),请检查您的代码是否严格符合标准,并且...
#pragma omp parallel for
并且在循环体内,您既要读取和写入函数自变量所指向的地址,又要进行大量的分支。作为一个没有根据的猜测,您可能正在实现定义的线程调用中破坏高速缓存,而MSVC可能会错误地避免使用别名规则将强制执行的中间存储。不可能告诉。