【问题标题】:Inconsistent atan2 results between 64-bit and 32-bit architecture [duplicate]64位和32位架构之间的atan2结果不一致[重复]
【发布时间】:2021-01-09 11:12:47
【问题描述】:

使用std::atan2 时,我得到的结果不同,具体取决于我是为 32 位架构交叉编译还是为(本机)64 位编译。

$ cat test.cc 
#include <cmath>
#include <stdio.h>

int main(int argc, char **argv) {
    printf("%f\n", std::atan2(366.470947f, -116.213623f));
}

$ gcc test.cc -o test -lm -ffp-contract=off -ffloat-store
$ ./test 
1.877880
$ gcc -m32 test.cc -o test -lm -ffp-contract=off -ffloat-store
$ ./test 
1.877881

我希望结果相同,因为我将应用程序移植到 64 位并且需要相同的浮点结果。如您所见,我已经尝试过-ffp-contract=off -ffloat-store,我知道这会导致浮点不一致。还有什么我想念的吗?还是三角函数根本没有以这种方式标准化?

我正在运行带有 gcc 7.5.0 的 Ubuntu 18.04.2。 CPU是i7-1065G7。

【问题讨论】:

标签: c++ gcc x86 floating-point precision


【解决方案1】:

不幸的是,您遇到了一个长期存在的 gcc 错误的变体:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323

问题在于 GCC 在不同情况下会或不会使用 80 位 FP 精度,而我们对其进行约束的能力是有限的。

使用-m32 强制 gcc 生成将在 i386 上运行的代码,因此别无选择,只能使用 80 位扩展精度 FPU 指令。原则上,您可以将 -mx32 用于 32 位内存模型,但如果您的运行时环境对此感到满意,则可以使用 x86-64。

但你还是会遇到麻烦:

  • -m32 将调用 atan2 的标准库版本,该版本从 387 FP 堆栈中提取参数,这与使用 xmm 寄存器传递参数的实现不同。
  • 通过优化,GCC 将在编译时使用扩展的双精度计算来计算结果。因此,例如-O3 你会得到 1.877881 和 -m32-m64,两者都与你从 32 位浮点计算中得到的值不一致。
  • 选项-fexcess-precision=standard——承诺避免这种更高精度的计算——只适用于C,而不是C++。见:https://gcc.gnu.org/wiki/FAQ#PR323

总之,情况很不理想,已经二十多年了

【讨论】:

  • 感谢您的详细回答。我可以在 C 中为受影响的数学函数编写包装器,使用 -fexcess-precision=standard 编译,然后将它们链接到我的 C++ 程序中吗?幸运的是,我能够更改 C++ 代码中的函数调用以引用我的包装版本,所以这将是一个不错的解决方案。
  • @kipi 我认为这应该可行!另一种选择是编写自己的超越函数(或使用其他人的)。这避免了编译时优化问题,然后您可以选择一个尽可能准确的实现,或者使用矢量化等。但这显然不是一个简单的选择:)
猜你喜欢
  • 2011-01-28
  • 2012-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多