我正在处理在 CUDA 中准确计算零阶 I0 的修正贝塞尔函数的问题。
很长一段时间以来,我一直根据论文使用有理切比雪夫近似
JM Blair,“修正贝塞尔函数 I_0(x) 和 I_1(x) 的有理切比雪夫近似”,数学。计算机,卷。28,名词。126,第 581-583 页,1974 年 4 月。
与 Matlab 提供的结果相比,它给出了 1e-29 量级的平均误差。不幸的是,对于我正在开发的新应用程序来说,这种看似高的准确性已经不够了。
Matlab 使用 DE Amos 开发的 Fortran 例程
Amos, DE,“复杂参数和非负阶贝塞尔函数的子程序包”,桑迪亚国家实验室报告,SAND85-1018,1985 年 5 月。
Amos,DE,“用于复杂参数和非负阶贝塞尔函数的便携式软件包”,反式。数学。软件,1986 年。
可从netlib/amos网站下载。
有一些方法可以在 C/C++ 代码中使用这些 Fortran 例程,方法是将它们编译到库文件中,然后使用 C/C++ 包装器(例如参见netlib_wrapping)。我想知道是否有任何方法可以从这些 Fortran 例程中生成设备功能,然后由 CUDA 内核调用)。
有关问题的更多详细信息
我有两个代码,一个是用 Matlab 编写的,一个是用 CUDA 编写的。两者都通过三个步骤进行操作:
1)通过修改后的贝塞尔函数 I0 和数据的零填充进行缩放;
2)快速傅里叶变换;
3)插值。
我将两者与“精确”结果进行比较:作为步骤 3) 的输出,Matlab 给出的相对均方根误差为 1e-10%,而 CUDA 为 1e-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%
,这让我认为不准确的来源是由于第一步,即计算修正的贝塞尔函数。
对于本次讨论的有趣发展