atan2f使用m32标志

时间:2017-02-03 22:56:45

标签: c floating-point 32bit-64bit

我将一些代码从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没有。

我尝试过的事情:

  1. 使用-ffloat-store

  2. 构建32位版本
  3. 使用-msse2 -mfpmath = sse构建32位版本

  4. 使用-mfpmath = 387构建64位版本

  5. 没有改变我的结果。

    (所有这些都基于这样的假设:它与32位与64位架构上的浮点运算方式有关。)

    问题:

    我有什么选择让他们给出相同的结果? (我可以使用编译器标志吗?)还有,这里发生了什么?

    我在i7机器上运行,如果有帮助的话。

1 个答案:

答案 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
  

这里发生了什么?

doublefloat的转换可能会达到最佳效果,但 arctangent 功能可能会在各种平台上关闭ULP1.914544701576233是下一个较小的float值,反映了稍低的反正切计算。

  

我有什么选择让他们给出相同的结果?

很少。代码可以从已建立的代码库中推送您自己的my_atan2()。然而,即使这可能会有微妙的实施差异。 @stark

相反,请考虑使代码检查能够容忍微小变化。