考虑这段 C 代码:
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
bool foo(int a, int b, int c, int d) {
double P = atan2(a, b);
double Q = atan2(c, d);
return P < Q;
}
bool bar(int a, int b, int c, int d) {
return atan2(a, b) < atan2(c, d);
}
int main() {
if (foo(2, 1, 2, 1)) puts("true"); else puts("false");
if (bar(2, 1, 2, 1)) puts("true"); else puts("false");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我用 编译它时gcc -lm -m64,它会打印
false …Run Code Online (Sandbox Code Playgroud) 考虑以下函数:
static inline float Eps(const float x) {
const float eps = std::numeric_limits<float>::epsilon();
return (1.0f + eps) * x - x;
}
float Eps1() {
return Eps(0xFFFFFFp-24f);
}
float Eps2() {
const float eps = std::numeric_limits<float>::epsilon();
const float x = 0xFFFFFFp-24f;
return (1.0f + eps) * x - x;
}
Run Code Online (Sandbox Code Playgroud)
在-O2with中-std=c++20,这两个函数都编译为一个函数,movss后跟一个ret针对 x86 的 using clang 16.0.0 和mov一个bx针对 ARM 的 with gcc 11.2.1。为 ARM 生成的程序集与返回值 ~5.96e-8 一致,但为 x86 生成的程序集则不然。 …
我对-ffp-contractGNU GCC中的标志有疑问(请参阅https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html)。
标志文档编写如下:
-ffp-contract=off禁用浮点表达式收缩。-ffp-contract=fast如果目标对它们有本机支持,则启用浮点表达式收缩,例如形成融合的乘法加法运算。-ffp-contract=on如果语言标准允许,则启用浮点表达式收缩。目前尚未实现,并且将其视为-ffp-contract=off。默认值为-ffp-contract=fast。
现在的问题是:
这个 C/C++ 简化测试用例:
int x = ~~~;
const double s = 1.0 / x;
const double r = 1.0 - x * s;
assert(r >= 0); // fail
Run Code Online (Sandbox Code Playgroud)
数值不稳定,并且符合断言。原因是最后的计算可以用FMA来完成,这就带来了r负面影响。
Clang 默认启用了 FMA(从版本 14 开始),因此它导致了一些有趣的回归。这是一个运行版本:https://godbolt.org/z/avvnnKo5E
有趣的是,如果将最后一个计算一分为二,则不会发出 FMA 并且结果始终为非负:
int x = ~~~;
const double s = 1.0 / x;
const double tmp = x * s;
const double r = 1.0 - tmp;
assert(r >= 0); // OK
Run Code Online (Sandbox Code Playgroud)
这是 IEEE754 / FP_CONTRACT 的保证行为,还是这是在玩火,应该找到一种数值更稳定的方法?我找不到任何迹象表明 fp 收缩仅意味着“本地”发生(在一个 …