准确计算修改后的贝塞尔函数 - 在CUDA中使用netlib Fortran例程?

时间:2013-01-02 14:38:36

标签: c++ cuda fortran

我正在处理在CUDA中准确计算零阶I0的修正贝塞尔函数的问题。

很长一段时间以来,我一直根据论文使用理性的切比雪夫近似

J.M。布莱尔,“修正的贝塞尔函数I_0(x)和I_1(x)的理性切比雪夫近似”,数学。 Comput。,vol。 28,n。 126,pp.581-583,1974年4月。

,与Matlab提供的结果相比,给出了1e-29的平均误差。不幸的是,这个看似很高的精度对于我正在研究的新应用来说已经不够了。

Matlab使用D.E开发的Fortran例程。摩

Amos,D.E。,“复杂论证和非负序的贝塞尔函数的子程序包”,桑迪亚国家实验室报告,SAND85-1018,1985年5月。

Amos,D.E。,“复杂论证和非负序的贝塞尔函数的便携式包”,Trans。数学。软件,1986年。

可从netlib/amos网站下载。

有些方法可以在C / C ++代码中使用这些Fortran例程,方法是在库文件中编译它们,然后使用C / C ++包装器(参见例如netlib_wrapping)。我想知道是否有任何方法可以使那些Fortran例程中的设备功能被CUDA内核调用。)

有关问题的详情

我有两个代码,一个用Matlab编写,另一个用CUDA编写。两者都有三个步骤:

1)通过修改的贝塞尔函数I0进行缩放和数据的零填充;

2) FFT ;

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%。最后,如果我用Matlab的步骤1)的输出提供CUDA的步骤2),那么步骤2)的rms错误变为1e-14%,这使我认为不准确的来源是由于第一步,即修改贝塞尔函数的计算。

对本次讨论的有趣发展

查看NVIDIA Developer Zone Forum

2 个答案:

答案 0 :(得分:3)

我想知道这是否可归因于浮点运算之间的精度差异。

有几件事需要检查

  1. Cuda 5增加了一些新的触发功能,可以更好地匹配您的计算格式。另外我认为自版本4以来的CUDA数学库有一些bessel函数,虽然我不确定这是否属实或者它们对你的问题有多么相关。
  2. 你能编写一个串行CPU版本进行测试吗?这将告诉您精度问题是否归因于优化,例如使用64位与80位表示的数字。关闭优化后,您的计算机将主要处理80位表示(也许matlab会这样做),而启用数学优化后,您的编译器可能会处理不太准确的64位表示。这相当于x87和SSE之间的差异。
  3. 不同的计算能力硬件的精度略有不同。例如,compute 2.0的FMA更准确,更接近于优化的x86。
  4. 是否有物理上的理由认为Matlab是正确的?当Matlab超调时,你的算法可能会低于结果。如果CUDA在Matlab没有进行操作时会发生这种情况。
  5. 如果必须,必须重新创建Matlab结果,您可以尝试通过将输出与不同的舍入技巧相匹配来调整代码的每个步骤。见表。
  6. 圆桌会议

    addition       | x + y        | __dadd_[rn|rz|ru|rd](x, y)
    multiplication | x * y        | __dmul_[rn|rz|ru|rd](x, y)
    Fused-Mult-Add | fma(x, y, z) | __fma_[rn|rz|ru|rd](x, y, z)
    reciprocal     | 1.0 / x      | __drcp_[rn|rz|ru|rd](x)
    division       | x / y        | __ddiv_[rn|rz|ru|rd](x, y)
    square root    | sqrt(x)      | __dsqrt_[rn|rz|ru|rd](x)
    
    mode | interpretation
    rn   | round to nearest, ties to even
    rz   | round towards zero
    ru   | round towards +∞
    rd   | round towards -∞
    

    来自http://developer.download.nvidia.com/assets/cuda/files/NVIDIA-CUDA-Floating-Point.pdf

答案 1 :(得分:0)

我找到了一个介绍性的技术讲座来回答你的问题。这是PDF的链接。 所以是的,这是可能的,但是我无法通过前面提到的脚本将遗留的fortran代码转换为CUDA C,也许直接联系开发人员。