相关疑难解决方法(0)

启用优化后会产生不同的浮点结果 - 编译器错误?

以下代码适用于Visual Studio 2008,有无优化.但它只适用于没有优化的G ++(O0).

#include <cstdlib>
#include <iostream>
#include <cmath>

double round(double v, double digit)
{
    double pow = std::pow(10.0, digit);
    double t = v * pow;
    //std::cout << "t:" << t << std::endl;
    double r = std::floor(t + 0.5);
    //std::cout << "r:" << r << std::endl;
    return r / pow;
}

int main(int argc, char *argv[])
{
    std::cout << round(4.45, 1) << std::endl;
    std::cout << round(4.55, 1) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

输出应该是:

4.5
4.6
Run Code Online (Sandbox Code Playgroud)

但是带有优化(O1- O3)的g ++ …

c++ optimization g++ c++-faq

103
推荐指数
3
解决办法
2万
查看次数

融合乘法加法和默认舍入模式

使用GCC 5.3,以下代码符合 -O3 -fma

float mul_add(float a, float b, float c) {
  return a*b + c;
}
Run Code Online (Sandbox Code Playgroud)

生成以下程序集

vfmadd132ss     %xmm1, %xmm2, %xmm0
ret
Run Code Online (Sandbox Code Playgroud)

我注意到GCC -O3已经在GCC 4.8中这样做了.

Clang 3.7带-O3 -mfma产品

vmulss  %xmm1, %xmm0, %xmm0
vaddss  %xmm2, %xmm0, %xmm0
retq
Run Code Online (Sandbox Code Playgroud)

但Clang 3.7与-Ofast -mfmaGCC生成的代码相同-O3 fast.

我很惊讶GCC的确如此,-O3因为从这个答案来看

除非允许使用宽松的浮点模型,否则不允许编译器融合分离的加法和乘法.

这是因为FMA只有一个舍入,而ADD + MUL有两个舍入.因此,编译器将通过融合违反严格的IEEE浮点行为.

但是,从这个链接说

无论FLT_EVAL_METHOD的值如何,任何浮点表达式都可以收缩,即,计算好像所有中间结果都具有无限范围和精度.

所以现在我感到困惑和担忧.

  1. GCC是否有理由使用FMA -O3?
  2. 融合是否违反了严格的IEEE浮点行为?
  3. 如果融合确实违反了IEEE浮点运算,那么GCC的回归__STDC_IEC_559__不是一个矛盾吗?

由于FMA 可以在软件中进行仿真,因此似乎应该有两个用于FMA的编译器开关:一个用于告诉编译器在计算中使用FMA,一个用于告诉编译器硬件具有FMA.


显然,这可以通过选项进行控制-ffp-contract.对于GCC,默认是-ffp-contract=fast和Clang不一样.其他选项例如 …

c gcc clang ieee-754 fma

14
推荐指数
1
解决办法
1347
查看次数

标签 统计

c ×1

c++ ×1

c++-faq ×1

clang ×1

fma ×1

g++ ×1

gcc ×1

ieee-754 ×1

optimization ×1