atan2f gives different results with m32 flag

|▌冷眼眸甩不掉的悲伤 提交于 2021-01-20 07:12:55

问题


I'm porting some code from 32 bit to 64 bit, and ensuring the answers are the same. In doing so, I noticed that atan2f was giving different results between the two.

I created this 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);
}

When built with:

gcc compilerTest.c -m32 -o 32bit.out -lm

it gives:

atan2f: 1.914544820785522
atan2: 1.914544820785522

When built with:

gcc compilerTest.c -o 64bit.out -lm

it gives:

atan2f: 1.914544701576233
atan2: 1.914544820785522

Note that atan2 gives the same result in both cases, but atan2f does not.

Things I have tried:

  1. Building the 32 bit version with -ffloat-store

  2. Building the 32 bit version with -msse2 -mfpmath=sse

  3. Building the 64 bit version with -mfpmath=387

None changed the results for me.

(All of these were based on the hypothesis that it has something to do with the way floating point operations happen on 32 bit vs 64 bit architectures.)

Question:

What are my options for getting them to give the same result? (Is there a compiler flag I could use?) And also, what is happening here?

I'm running on an i7 machine, if that is helpful.


回答1:


This is easier to see in hex notation.

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?

The conversion from double to float can be expected to be optimal, yet arctangent functions may be a few ULP off on various platforms. The 1.914544701576233 is the next smaller float value and reflects the slightly inferior arctangent calculation.


What are my options for getting them to give the same result?

Few. Code could roll your own my_atan2() from an established code base. Yet even that may have subtle implementation differences. @stark

Instead, consider making code checking tolerant of the minute variations.



来源:https://stackoverflow.com/questions/42034329/atan2f-gives-different-results-with-m32-flag

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!