CUDA でゼロ次 I0 の修正ベッセル関数を正確に計算する問題を扱っています。
論文によると、長い間、私は合理的なチェビシェフ近似を使用してきました。
JM Blair、「修正ベッセル関数 I_0(x) および I_1(x) の有理チェビシェフ近似」、Math. 、vol.28、n。126、pp. 581-583、1974 年 4 月。
これは、Matlab によって提供された結果と比較して、1e-29 のオーダーの平均誤差を示します。残念ながら、この一見高い精度は、私が取り組んでいる新しいアプリケーションには十分ではありません。
Matlab は、DE Amos によって開発された Fortran ルーチンを使用します。
デ・エイモス、「複雑な引数と非負の順序のベッセル関数のサブルーチン パッケージ」、サンディア国立研究所レポート、SAND85-1018、1985 年 5 月。
Amos、DE、「複雑な引数と非負の順序のベッセル関数のポータブル パッケージ」、Trans。算数。ソフトウェア、1986年。
netlib/amos Web サイトからダウンロードできます。
これらの Fortran ルーチンを C/C++ コードで使用するには、ライブラリ ファイルでコンパイルしてから C/C++ ラッパーを使用する方法があります (たとえば、netlib_wrappingを参照)。これらの Fortran ルーチンからデバイス関数を作成し、CUDA カーネルによって呼び出されるようにする方法があるかどうか疑問に思っています)。
問題の詳細
1 つは Matlab で、もう 1 つは CUDA で記述された 2 つのコードがあります。どちらも次の 3 つのステップで動作します。
1)修正ベッセル関数 I0 によるスケーリングとデータのゼロ パディング。
2) FFT ;
3)補間。
両方を「正確な」結果と比較しています。ステップ 3) の出力として、Matlab は 1e-10 % の相対二乗平均平方根誤差を与え、CUDA は 1e-2% であるため、その理由を調査し始めました。
2 つのコードの最初のステップの二乗平均平方根の差、つまり100*sqrt(sum(abs(U_Matlab_step_1-U_CUDA_step_1).^2))/sqrt(sum(abs(U_Matlab_step_1).^2))
は0%
(mean(mean(abs(U_Matlab-U_CUDA)))=6e-29
代わりに) なので、良いと言えます。残念ながら、ステップ 2 に進むと、エラーが発生し2e-4%
ます。最後に、CUDA のステップ 2) に Matlab のステップ 1) の出力を入力すると、ステップ 2) の rms エラー1e-14%
は修正されたベッセル関数の。
この議論の興味深い展開について
NVIDIA 開発者ゾーン フォーラムをご覧ください