7

MSDN 文章中,它提到当 fp:fast 模式被启用时,像加法标识 ( a±0.0 = a, 0.0-a = -a) 这样的操作是不安全的。有没有a+0 != a在这种模式下的例子?

编辑:正如下面提到的那样,在进行比较时通常会出现这种问题。我的问题来自比较,psedocode 如下所示:

for(i=0;i<v.len;i++)
{
  sum+=v[i];
  if( sum >= threshold) break;
}

0它在添加( )值后中断v[i]v[i]不是来自计算,它是分配的。我知道如果我v[i]是来自计算,那么舍入可能会起作用,但为什么即使我给出v[i]一个零值,我仍然有这个sum < threshold但是sum + v[i] >= threshold

4

4 回答 4

3

它“不安全”的原因是编译器假设为零的内容可能不会真正最终为零,因为舍入错误。

以这个例子为例,它在 32 位浮点数允许的精度边缘添加了两个浮点数:

    float a = 33554430, b = 16777215;
    float x = a + b;
    float y = x - a - b;
    float z = 1;
    z = z + y;

使用 fp:fast,编译器会说“因为 x = a + b,y = x - a - b = 0,所以 'z + y' 就是 z”。但是,由于舍入误差,y 实际上最终是 -1,而不是 0。所以如果没有 fp:fast,你会得到不同的结果。

于 2013-10-17T17:37:44.900 回答
2

这并不是说“固定”之类的东西,“如果您设置 /fp:fast,并且变量 a 恰好是 3.12345,那么 a+0 可能不是 a”。意思是当您设置 /fp:fast 时,编译器将采用快捷方式,这意味着如果您计算 a+0,然后将其与您为 a 存储的内容进行比较,则不能保证它们会相同。

关于这类问题(计算机上的浮点计算所特有的)有一篇很棒的文章:http: //www.parashift.com/c++-faq-lite/floating-point-arith2.html

于 2013-10-17T17:27:16.567 回答
2

如果a-0.0,那么a + 0.0是 +0.0。

于 2013-10-17T18:16:48.720 回答
1

它提到当启用 fp:fast 模式时,诸如加法身份 (a±0.0 = a, 0.0-a = -a) 之类的操作是不安全的。

那篇文章说的是

当启用 fp:fast 模式时,优化器可以使用以下任何(不安全的)代数规则:

然后列出 a±0.0 = a 和 0.0-a = -a

并不是说启用 fp:fast 时这些身份是不安全的。就是说这些身份对于 IEEE 754 浮点算术来说是不正确的,但是 /fp:fast 将优化,就好像它们是真的一样。

我不确定是否有一个例子表明它a + 0.0 == a是错误的(显然 NaN 除外),但 IEEE 754 有很多微妙之处,例如何时应该截断中间值。一种可能性是,如果您有一些包含 的表达式+ 0.0,这可能会导致 IEEE 754 要求对中间值进行截断,但是 /fp:fast 将生成不进行截断的代码,因此会产生后续结果可能与 IEEE 754 严格要求的有所不同。


使用 Pascal Cuoq 的信息,这是一个基于 /fp:fast 产生不同输出的程序

#include <cmath>
#include <iostream>

int main() {
    volatile double a = -0.0;
    if (_copysign(1.0, a + 0.0) ==  _copysign(1.0, 0.0)) {
        std::cout << "correct IEEE 754 results\n";
    } else {
        std::cout << "result not IEEE 754 conformant\n";
    }
}

当使用 /fp:fast 构建时,程序会输出“结果不符合 IEEE 754”,而使用 /fp:strict 会导致程序输出“正确的 IEEE 754 结果”。

于 2013-10-17T19:10:56.177 回答