2016-08-18 6 views
-4

計算のためにOpenCLカーネルがあります。私は1つのスレッドだけがCPUコードで異なる結果を出すことが分かった。私はvs2010 x64リリースモードを使用しています。OpenCLカーネル浮動小数点除算で異なる結果が出る

いくつかの例でOpenCLコードを調べると、興味深い結果がいくつか見つかりました。カーネルコードのテスト例を以下に示します。 Iは、OpenCLのカーネルの3症例を試験

、精度がprintf("%.10f", fval);

ケース1によって確認された:

float fval = (10296184.0)/(float)(x*y*z); // which gives result fval = 3351.6225585938 

float fval = (10296184.0f)/(float)(x*y*z); // which gives result fval = 3351.6225585938 

変数は:int x,y, z

これらの値はいくつかの操作によって計算されます。その値はx = 12、y = 16、z = 16です。

ケース2:

float fval = (10296184.0)/(float)(12*16*16); // which gives result fval = 3351.6223144531 

float fval = (10296184.0f)/(float)(12*16*16); // which gives result fval = 3351.6223144531 

ケース3:私は二つの表現の上に使用してfvalの差を計算する際10296184.0を使用する場合

しかし、結果は0です。

float fval = (10296184.0)/(float)(x*y*z) - (10296184.0)/(float)(12*16*16); // which gives result fval = 0.0000000000

float fval = (10296184.0f)/(float)(x*y*z) - (10296184.0f)/(float)(12*16*16); // which gives result fval = 0.0001812663

誰もがその理由を説明したり、私にいくつかのヒントを与えるだろうか?

+3

[浮動小数点演算が壊れていますか?](http://stackoverflow.com/questions/588004/is-floating-point-math-broken)を参照してください。これらの不正確さは、いくつかの制約が私に劣った 'float'を使用させない限り、私はいつも' double'を使います(同じことに苦しんでいますが)。 –

+0

それ以上の精度が必要な場合は、倍精度FPがGPU上のものである理由です。レンダリングにはほとんど応用されていません。 –

+0

「3351.6226,3351.6223および0」の値がどのようにして決定されたかを記入してください。 'printf("%f "、...)'、デバッガなど – chux

答えて

3

いくつかの観察:

float

2つの値が1 ULPによって異なります。したがって、結果は最小量だけ異なります。

// Float ULP in the 2's place here 
//  v 
0x1.a2f3ea0000000p+11 3351.622314... // OP's lower float value 
0x1.a2f3eaaaaaaabp+11 3351.622395... // higher precision quotient 
0x1.a2f3ec0000000p+11 3351.622558... // OP's higher float value 

(10296184.0)/(float)(12*16*16)期待数学の解答へ近い結果であるとして時間をコンパイルで計算されます。

float fval = (10296184.0)/(float)(x*y*z)は、の実行で計算されます。

floatの変数が使用されていることを考慮すると、このコードではdoubleの数値でコードが実行されています。これはdoublefloatプロダクトのプロモーション)であるdoubleによって定数除算され、double商になり、floatに変換されて保存されます。私は10296184.0f - f - が使用されていることを期待しています。そして、計算はすべてfloatとして実行されている可能性があります。

Cでは、異なる丸めモードが可能です。FLT_ROUNDSこれはコンパイル時および実行時に異なる場合があり、の場合はの違いを説明しています。 fegetround()の結果を知る(この関数は現在の丸め方向を取得します)。

OP は、速度の精度を犠牲にするさまざまなコンパイラの最適化を採用しています。


C は、算術演算の精度ですを指定し、まだ最後のULPに優れていませんが、品質プラットフォーム上*/+ - sqrt() modf()と予想されなければなりません。私はコードが弱い数学の実装に苦しんでいると思う。

関連する問題