处理OpenCL粒子系统中缺乏浮点精度

Pri*_*ett 2 floating-point precision opencl

我正在编写一个基于OpenCL的粒子系统来加速大规模网络的可视化.实质上,这是一个两阶段问题,其中第一阶段对每个粒子施加负重力(典型的n体问题),因此它们全部排斥并且第二阶段然后基于粒子之间的边缘(或弹簧)吸引粒子.

在重力算法的每次迭代期间,每个粒子的位置(表示为一对浮子)受到彼此距离的影响(经典物理模型,没有阻力,保持简单).

在一个具有完美间隔的方形阵列粒子的情况下,重力的应用应该导致跨越X和Y轴的对称性.这在重力应用开始时就是如此,但随着时间的推移,将大量浮点数加在一起所固有的精度不足会导致小的不均匀偏差.这反过来传播通过整个n体系统并且发生对称性的损失.

避免这种情况的一种简单方法是使用双精度数字,但MacBook Pro上的GeForce 9600M GT不支持双精度数字.那么,在OpenCL中处理这些问题的好方法是什么?我已经考虑过截断我添加到几个小数的浮点数以避免这个问题,但这看起来有点笨拙.

use*_*368 14

您已经遇到了大多数对数值分析领域至关重要的问题; 你应该准备好解读一下这些问题通常是如何处理的.

首先,如果您的问题具有对称性,您可以利用它来减少所需的计算量,并且还可以消除由于数值错误导致的任何自发对称性破坏.

其次,要意识到即使在处理相同的有限精度时,并非所有算法都相同:某些算法在数值上比其他算法更稳定.使用更高精度的算法并不能消除数值不稳定性,只需要花费更长的时间才能显现出来.您的重力模拟当前可能实现了与Euler方法相当的方法.无需切换到双精度,您可以使用更高阶的方法(例如Runge-Kutta)使模拟更加稳定/准确.

最后,听起来你正在做强制导向的图形布局.简单地向前运行物理模拟很容易找到局部最优,高度依赖于起始位置,并且(正如您所发现的)通常非常不稳定.链接的维基页面提到了其他几种可以更好地解决问题的方法.


Jon*_*rsi 7

这是一个非常普遍的问题; 即使在CPU上,有时您也希望避免使用双精度来避免内存开销/带宽因素为2.

为GPU编写的许多分子动力学和n体代码使用"混合精度"算法; 它们将粒子位置和速度存储为单个精度,但是它们使用双精度进行一些关键操作 - 通常用于存储位置差异,并累积加速度.(谷歌搜索"混合精度""分子动力学""n体"给出了吨的结果).

这样可以减少双精度计算的次数,但不会减少到零.要实现比硬件原生支持的更高精度算术,您可以进行软件仿真,使用两个浮点模拟双精度.有一个古老的fortran库dsfun90实现了这个,并且在这个NVidia论坛中有人在CUDA中实现了类似的东西(基于NVIDIA的Mandelbrot示例中的操作).我不知道一个OpenCL实现,但从CUDA复制它应该非常简单.显然它没有本机双打那么快,但如果只是为了几个关键操作,它就不那么糟糕了.