2017-02-03 20 views
3

Я портирую код с 32 до 64 бит и гарантирую, что ответы будут одинаковыми. При этом я заметил, что atan2f дает разные результаты между ними.atan2f дает разные результаты с флагом m32

Я создал этот мин репро:

#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. Построения 32 разрядной версии с -ffloat-магазином

  2. Построения 32-битную версии с -msse2 -mfpmath = сс

  3. Построение 64-битной версии с -mfpmath = 387

Ничего не меняли результаты для меня.

(Все они были основаны на предположении, что она имеет что-то делать с тем, как операции с плавающей точкой произойдет на 32 бит против 64 разрядных архитектур.)

Вопрос:

Каковы мои варианты для получения того же результата? (Есть ли флаг компилятора, который я мог бы использовать?) А также, что здесь происходит?

Я работаю на машине i7, если это полезно.

+0

Prinitng with '" atan2f:% .15f \ n "' _may be_ недостаточно точный. Используйте ''% .16e \ n "' или лучше ''% a \ n "' для исследования. – chux

+0

Почему вы ожидаете, что две разные библиотеки будут предоставлять точно такие же результаты и какие размеры имеют 'float' на обеих платформах? Различия не в том, что можно было бы волноваться. – Olaf

+0

Обратите внимание, что '1.914544701576233' и' 1.914544820785522' отличаются на 2 бита в [ULP] (https://en.wikipedia.org/wiki/Unit_in_the_last_place) – chux

ответ

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 можно ожидать, чтобы быть оптимальным, но арктангенс функции могут быть несколько ULP прочь на различных платформах. Значение 1.914544701576233 является следующим меньшим значением float и отражает расчеты с меньшим коэффициентом арктанга.


Каковы мои варианты для получения их, чтобы дать тот же результат?

Немного. Код может свернуть ваш my_atan2() от установленного базы кода. Но даже это может иметь тонкие различия в реализации. @stark

Вместо этого рассмотрите вопрос о том, как сделать проверку кода терпимой к небольшим изменениям.

+0

Я думаю, что вопрос спрашивает, какой флаг может сделать эти идентичные (кроме m32) – TinyTheBrontosaurus

+0

Спасибо. К сожалению, я работаю с устаревшей базой кода, поэтому сделать ее толерантной в отношении минутных вариаций нетривиальной. Увы, догадаться, мне придется поработать над проблемой. – powerss

+0

@TinyTheBrontosaurus Правда, использование _flag_, возможно, было одним из способов решения этой проблемы. Тем не менее я не видел, чтобы сообщение ограничивалось простым изменением параметров gcc, но более открытым. – chux