質問

なぜ使用することが必須です -ffast-math G ++でループのベクトル化を実現する doubles?私は好きではありません -ffast-math 精度を失いたくないからです。

役に立ちましたか?

解決

必ずしも精度を失うわけではありません -ffast-math. 。それはの取り扱いにのみ影響します NaN, Inf など、および操作が実行される順序。

GCCに計算を並べ替えたり簡素化したりしたくない特定のコードがある場合は、変数を使用して使用しているとマークできます。 asm 声明。

たとえば、次のコードは丸め操作を実行します f. 。ただし、2つ f += gf -= g 操作はGCCによって最適化される可能性があります:

static double moo(double f, double g)                                      
{                                                                          
    g *= 4503599627370496.0; // 2 ** 52                                    
    f += g;                                                                
    f -= g;                                                                
    return f;                                                            
}                                                                     

x86_64では、これを使用できます asm GCCにその最適化を実行しないように指示する声明:

static double moo(double f, double g)                                      
{                                                                          
    g *= 4503599627370496.0; // 2 ** 52                                    
    f += g;                                                                
    __asm__("" : "+x" (f));
    f -= g;
    return f;
}

残念ながら、各アーキテクチャにこれを適応させる必要があります。 PowerPCで使用します +f それ以外の +x.

他のヒント

ベクトル化は、あなたが異なる結果を持っている可能性があることを意味するか、または浮遊点信号/例外を逃すことを意味する可能性があるためです。

32ビットx86をコンパイルしている場合、GCCとG ++のデフォルトでx87を使用することにデフォルトで、64ビットでdefault sseになりますが、x87は同じ計算に対して異なる値を生成するため、G ++はありません。使用しない限り、同じ結果が得られることを保証できない場合は、ベクトル化を検討します -ffast-math または、それがオンになっているフラグの一部。

基本的には、ベクトル化されたコードのフローティングポイント環境に帰着します。非ベクトル化コードのコードと同じではない場合があります。

-fno-math-errno -fno-trapping-math -fno-signaling-nans -fno-rounding-math

ただし、最初にこれらのオプションを調べて、プログラムの正確性に影響を与えないようにしてください。 -ffinite-math-only 助けになるかもしれません

なぜなら -ffast-math 有効にします オペランドの並べ替え これにより、多くのコードをベクトル化できます。

たとえば、これを計算します

sum = a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + … a[99]

コンパイラはそうです 必要 追加するために 順次 それなし -ffast-math, 、フローティングポイント数学は通勤でも連想的でもないからです。

それが同じ理由です コンパイラが最適化できない理由 a*a*a*a*a*a(a*a*a)*(a*a*a) それなし -ffast-math

つまり、非常に効率的な水平ベクトルが追加されない限り、ベクトル化が利用できないことを意味します。

ただし、場合 -ffast-math 有効になっていると、式を計算できます このような (見る A7. Auto-Vectorization)

sum0 = a[0] + a[4] + a[ 8] + … a[96]
sum1 = a[1] + a[5] + a[ 9] + … a[97]
sum2 = a[2] + a[6] + a[10] + … a[98]
sum3 = a[3] + a[7] + a[11] + … a[99]
sum’ = sum0 + sum1 + sum2 + sum3

これで、コンパイラは各列を並列に追加することで簡単にベクトル化でき、最後に水平方式の追加を実行できます。

します sum’ == sum?場合にのみ (a[0]+a[4]+…) + (a[1]+a[5]+…) + (a[2]+a[6]+…) + ([a[3]+a[7]+…) == a[0] + a[1] + a[2] + … これは、常に順守しない連想性の下に保持されます。指定 /fp:fast この簡単な計算のために、コンパイラがコードをより速く実行するように変換して、最大4倍高速に実行できます。

あなたは速いですか、それとも正確ですか? -a7。自動ベクトル化

によって有効になる場合があります -fassociative-math GCCのフラグ

さらなる測定値

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top