2017-02-03 2 views
3

Ich portiere Code von 32 Bit auf 64 Bit, und stellen Sie sicher, dass die Antworten die gleichen sind. Dabei habe ich festgestellt, dass Atan2f unterschiedliche Ergebnisse zwischen den beiden ergeben hat.atan2f gibt andere Ergebnisse mit m32 flag

Ich habe dieses 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); 
} 

Wenn mit eingebautem:

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

es gibt:

atan2f: 1.914544820785522 
atan2: 1.914544820785522 

Wenn mit eingebautem:

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

es gibt:

atan2f: 1.914544701576233 
atan2: 1.914544820785522 

Hinweis gibt, dass atan2 das gleiche Ergebnis in beiden Fällen aber atan2f nicht.

Dinge, die ich habe versucht:

  1. Aufbau der 32-Bit-Version mit -ffloat-store

  2. Aufbau der 32-Bit-Version mit -msse2 -mfpmath = sse

  3. der Aufbau der 64-Bit-Version mit -mfpmath = 387

Keine hat die Ergebnisse für mich verändert.

(Alle diese wurden basiert auf der Hypothese, dass es etwas mit der Art und Weise Gleitkommaoperationen passieren auf 32 Bit vs 64-Bit-Architekturen zu tun.)

Frage:

Was sind meine Optionen, um sie zum gleichen Ergebnis zu bringen? (Gibt es ein Compiler-Flag, das ich verwenden könnte?) Und was passiert hier?

Ich bin auf einem i7-Computer ausgeführt, wenn das hilfreich ist.

+0

Prinitng mit '" atan2f:% .15f \ n "' _ kann _ ungenügend genau sein. Verwende '"% .16e \ n "' oder besser '"% a \ n "' zur Untersuchung. – chux

+0

Warum erwarten Sie, dass zwei verschiedene Bibliotheken genau die gleichen Ergebnisse liefern und welche Größen "float" auf beiden Plattformen haben? Die Unterschiede sind nicht, dass man sich sorgen würde. – Olaf

+0

Beachten Sie, dass sich '1.914544701576233' und' 1.914544820785522' um 2 Bits in der [ULP] (https://en.wikipedia.org/wiki/Unit_in_the_last_place) unterscheiden. – chux

Antwort

0

Dies ist einfacher in Hex-Notation zu sehen.

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 

, was hier geschieht?

Die Umwandlung von double zu float kann optimal erwartet werden, noch arctangent Funktionen können einige ULP off auf verschiedenen Plattformen sein. Der 1.914544701576233 ist der nächstkleinere float Wert und spiegelt die etwas schlechtere Arcustangensberechnung wider.


Was sind meine Optionen für sie immer das gleiche Ergebnis geben?

Wenige. Code könnte Ihre eigene my_atan2() von einer etablierten Code-Basis rollen. Aber selbst das mag subtile Implementierungsunterschiede haben. @stark

Stattdessen sollten Sie in Betracht ziehen, die Code-Überprüfung tolerant gegenüber den kleinsten Variationen zu machen.

+0

Ich denke, die Frage ist, welche Flagge kann diese identisch machen (außer m32) – TinyTheBrontosaurus

+0

Danke. Leider arbeite ich mit einer Legacy-Code-Basis, daher ist es nicht trivial, die winzigen Variationen tolerant zu machen. Leider muss ich das Problem umgehen. – powerss

+0

@TinyTheBrontosaurus True, die Verwendung eines _flag_ könnte ein Ansatz sein, um dieses Problem zu lösen. Dennoch sah ich die Post nicht als Beschränkung auf eine einfache gcc-Option, sondern offen. – chux

Verwandte Themen