2017-02-03 10 views
3

私は32ビットから64ビットにいくつかのコードを移植しており、答えが同じであることを保証しています。その際、私はatan2fが2人の間で異なった結果を出していることに気付きました。atan2fはm32フラグで異なる結果を返します

gcc compilerTest.c -o 64bit.out -lm 
:で構築された場合

atan2f: 1.914544820785522 
atan2: 1.914544820785522 

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

ことができます:で構築された場合

#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); 
} 

私はこの分REPROを作成しました

それは与える:

atan2f: 1.914544701576233 
atan2: 1.914544820785522 

注意にatan2は、どちらの場合も同じ結果が得られますが、atan2fないこと。私が試みた

もの: -msse2 -mfpmath = SSE

  • 32ビットバージョンをビルド-ffloat店舗

  • 32ビットバージョンをビルド

    1. -mfpmath = 387での64ビットバージョンの構築

    私の結果は変更されていません。

    (。これらのすべては、それが浮動小数点演算は、64ビット・アーキテクチャ対32ビットで発生方法とは何かを持っているという仮説に基づいていた)

    質問:

    私は何です同じ結果を得るためのオプション? (使用できるコンパイラフラグはありますか?)また、ここで何が起こっていますか?

    私はi7マシンで実行していますが、それが役に立ちます。

  • +0

    atan2f:%.15f \ n "' _は十分に正確ではないかもしれません。 '"%.16e \ n "'またはそれ以上の "%a \ n" 'を使って調査してください。 – chux

    +0

    なぜ2つの異なるライブラリが全く同じ結果を提供し、どのプラットフォームのサイズが両方のプラットフォームで 'float'になるのでしょうか?違いは心配するものではありません。 – Olaf

    +0

    「1.914544701576233」と「1.914544820785522」は、[ULP](https://en.wikipedia.org/wiki/Unit_in_the_last_place)の2ビットで異なることに注意してください。 – chux

    答えて

    0

    これは、16進表記で分かりやすくなっています。ここで何が起こっているのか

    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 Trueを使用すると、_flag_を使用して、この問題を解決する1つのアプローチとなる可能性があります。しかし、私は単純なgccオプションの変更に限られているとは思っていませんでしたが、もっとオープンです。 – chux

    関連する問題