atan2f 使用 m32 标志给出不同的结果
atan2f gives different results with m32 flag
我正在将一些代码从 32 位移植到 64 位,并确保答案相同。在这样做的过程中,我注意到 atan2f 在两者之间给出了不同的结果。
我创建了这个最小重现:
#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 构建 32 位版本
使用 -msse2 -mfpmath=sse 构建 32 位版本
使用 -mfpmath=387 构建 64 位版本
None 为我更改了结果。
(所有这些都是基于这样的假设,即它与浮点运算在 32 位和 64 位架构上的发生方式有关。)
问题:
我有哪些选择可以让他们给出相同的结果? (是否有我可以使用的编译器标志?)还有,这里发生了什么?
我 运行 在 i7 机器上,如果有帮助的话。
这在十六进制表示法中更容易看出。
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
what is happening here?
从 double
到 float
的转换可以预期是最佳的,但是 arctangent 函数可能有一些 ULP 关闭各种平台。 1.914544701576233
是下一个较小的 float
值,反映了略差的反正切计算。
What are my options for getting them to give the same result?
很少。代码可以从 已建立的 代码库中推出您自己的 my_atan2()
。然而,即使那样也可能存在细微的实施差异。
相反,考虑让代码检查容忍微小的变化。
我正在将一些代码从 32 位移植到 64 位,并确保答案相同。在这样做的过程中,我注意到 atan2f 在两者之间给出了不同的结果。
我创建了这个最小重现:
#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 构建 32 位版本
使用 -msse2 -mfpmath=sse 构建 32 位版本
使用 -mfpmath=387 构建 64 位版本
None 为我更改了结果。
(所有这些都是基于这样的假设,即它与浮点运算在 32 位和 64 位架构上的发生方式有关。)
问题:
我有哪些选择可以让他们给出相同的结果? (是否有我可以使用的编译器标志?)还有,这里发生了什么?
我 运行 在 i7 机器上,如果有帮助的话。
这在十六进制表示法中更容易看出。
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
what is happening here?
从 double
到 float
的转换可以预期是最佳的,但是 arctangent 函数可能有一些 ULP 关闭各种平台。 1.914544701576233
是下一个较小的 float
值,反映了略差的反正切计算。
What are my options for getting them to give the same result?
很少。代码可以从 已建立的 代码库中推出您自己的 my_atan2()
。然而,即使那样也可能存在细微的实施差异。
相反,考虑让代码检查容忍微小的变化。