我将一些代码从32位移植到64位,并确保答案是相同的。在这样做时,我注意到atan2f在两者之间给出了不同的结果。
我创建了这个min repro:
#include <stdio.h>
#include <math.h>
void testAtan2fIssue(float A, float B)
{
float atan2fResult = atan2f(A, B);
printf("atan2f: %.15f\n", atan2fResult);
float atan2Result = atan2(A, B);
printf("atan2: %.15f\n", atan2Result);
}
int main()
{
float A = 16.323556900024414;
float B = -5.843180656433105;
testAtan2fIssue(A, B);
}
建造时:
gcc compilerTest.c -m32 -o 32bit.out -lm
它给出了:
atan2f: 1.914544820785522
atan2: 1.914544820785522
建造时:
gcc compilerTest.c -o 64bit.out -lm
它给出了:
atan2f: 1.914544701576233
atan2: 1.914544820785522
请注意,atan2在两种情况下都给出相同的结果,但atan2f没有。
我尝试过的事情:
使用-ffloat-store
使用-msse2 -mfpmath = sse构建32位版本
使用-mfpmath = 387构建64位版本
没有改变我的结果。
(所有这些都基于这样的假设:它与32位与64位架构上的浮点运算方式有关。)
问题:
我有什么选择让他们给出相同的结果? (我可以使用编译器标志吗?)还有,这里发生了什么?
我在i7机器上运行,如果有帮助的话。
答案 0 :(得分:0)
以十六进制表示法更容易看到。
void testAtan2fIssue(float A, float B) {
double d = atan2(A, B);
printf(" atan2 : %.13a %.15f\n", d, d);
float f = atan2f(A, B);
printf(" atan2f: %.13a %.15f\n", f, f);
printf("(float) atan2 : %.13a %.15f\n", (float) d, (float) d);
float f2 = nextafterf(f, 0);
printf("problem value : %.13a %.15f\n", f2, f2);
}
// _ added for clarity
atan2 : 0x1.ea1f9_b9d85de4p+0 1.914544_797857041
atan2f: 0x1.ea1f9_c0000000p+0 1.914544_820785522
(float) atan2 : 0x1.ea1f9_c0000000p+0 1.914544_820785522
problem value : 0x1.ea1f9_a0000000p+0 1.914544_701576233
这里发生了什么?
从double
到float
的转换可能会达到最佳效果,但 arctangent 功能可能会在各种平台上关闭ULP。 1.914544701576233
是下一个较小的float
值,反映了稍低的反正切计算。
我有什么选择让他们给出相同的结果?
很少。代码可以从已建立的代码库中推送您自己的my_atan2()
。然而,即使这可能会有微妙的实施差异。 @stark
相反,请考虑使代码检查能够容忍微小变化。