gcc C/C++强制浮点操作顺序的技巧

v1uwarro  于 6个月前  发布在  C/C++
关注(0)|答案(1)|浏览(76)

我正在寻找方法来强制gcc遵守特定的操作顺序(它不一定是最小化浮点错误的顺序,只是我碰巧想要的顺序)关于特定代码段的双精度运算,同时允许在其他地方使用完整的-O3 -funsafe-math-optimizations。我已经看到了一些关于这个问题的帖子:
Are floating point operations in C associative?
https://devblogs.microsoft.com/cppblog/do-you-prefer-fast-or-precise/
C/C++ Math Order of Operation
上面的链接讨论了全局选项,但我想了解是否存在本地编译器指令。例如,在进行硬件合成时,可以强制编译器逐字合成逻辑表达式而不进行任何约简。
例如考虑

#include <iostream>
#include <string>
#include <iomanip>

using std::cout;

int main()
{
    double a = 1.0 + 1.3e-16;
    double b = 1.0;
    double c = 100.0;

    double d = (a - b) / c;
    double e = a / c - b / c;

    cout << std::scientific;
    cout << "Calculation d = " << d << "\n";
    cout << "Calculation e = " << e << "\n";

    double f = 1.0;
    double g = 2e-15;
    double h = 1.0;
    double i = 1e-15;

    double j = (f + g) - (h + i);
    double k = (f - h) + (g - i);
    double m = f + g - h - i;
    double n = f - h + g - i;

    cout << "Calculation j = " << j << "\n";
    cout << "Calculation k = " << k << "\n";
    cout << "Calculation m = " << m << "\n";
    cout << "Calculation n = " << n << "\n";
}

字符串
使用http://cpp.sh,我得到

Calculation d = 2.220446e-18
Calculation e = 1.734723e-18
Calculation j = 8.881784e-16
Calculation k = 1.000000e-15
Calculation m = 9.984014e-16
Calculation n = 1.000000e-15


这与我使用的优化级别无关,所以看起来编译器将根据表达式按照我期望的顺序计算,甚至还保持+/-的左右顺序,但是当优化打开时,这是绝对保证的吗?
我可以想到一个场景,例如,其中一个操作数已经位于某个有用的寄存器中,因此它将保存一些内存,以便以与我编写的顺序不同的顺序进行计算,但将保持符号正确性。
基本上我不能开始尝试不同的方法来解决这个问题,例如,我读到声明子产品为volatile变量会有帮助,因为我的例子没有显示问题。所以我想知道这是否真的是一个没有问题的问题,如果不是,有什么技巧存在。

bprjcwpo

bprjcwpo1#

这个答案晚了4年,但是你可以使用GCC的__attribute__指令来禁用一个函数中不安全的数学优化。这个函数可以是静态内联的,所以它仍然内联,但完全符合指定的操作顺序(因此没有性能影响)。

static inline __attribute__((__optimize__("no-associative-math", "no-unsafe-math-optimizations", "no-fast-math"))) double myfunction( double a, double b )
{
  ...
}

字符串
我建议将__attribute__放在#define中,以保持可读性。

相关问题