我正在寻找方法来强制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变量会有帮助,因为我的例子没有显示问题。所以我想知道这是否真的是一个没有问题的问题,如果不是,有什么技巧存在。
1条答案
按热度按时间bprjcwpo1#
这个答案晚了4年,但是你可以使用GCC的
__attribute__
指令来禁用一个函数中不安全的数学优化。这个函数可以是静态内联的,所以它仍然内联,但完全符合指定的操作顺序(因此没有性能影响)。字符串
我建议将
__attribute__
放在#define中,以保持可读性。