在 32 位机器上,当我不将其结果存储在变量中时,atan2 是不确定的。为什么?

Nie*_*kob 15 c c++ floating-point 32-bit ieee-754

考虑这段 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
false
Run Code Online (Sandbox Code Playgroud)

正如预期的那样。但是,当我用 编译它时gcc -lm -m32,输出是

false
true
Run Code Online (Sandbox Code Playgroud)

为什么将结果存储在变量中这样一个微不足道的区别会改变代码的行为?是不是因为浮点寄存器是 80 位的?我应该如何编写代码以避免像这样的怪异?

(我最初bar在 C++ 程序中使用变体作为 的比较函数std::sort。这触发了未定义的行为,因为comp(a, a)返回 true - 我应该如何在没有 UB 的情况下通过它们的角度比较向量?)

到目前为止的评论摘要

似乎一致认为这是因为结果四舍五入到double. C/C++ 标准允许这样做,即使结果不同。

将输入比较为 的解决方法a * d < b * c,这在本示例中确实有帮助。但是,我希望将来避免此类问题,而不仅仅是修复错误并继续前进。如果输入本身是doubles ,问题仍然可能会出现。

我承认由于浮点运算的性质,比较可能不准确,但是如果角度如此接近,我仍然希望实现 所需的严格弱排序std::sort,这样就不会发生 UB。