Cuda中的runif函数

时间:2015-11-21 17:47:37

标签: random cuda distribution

我正在尝试在Cuda中实现Metropolis-Hastings算法。对于这个算法,我需要能够生成许多具有不同范围的均匀随机数。因此,我想有一个名为runif(min,max)的函数,它返回此范围内的均匀分布数。必须在实际实现算法的另一个函数内多次调用此函数。

基于this帖子,我试图将显示在那里的代码放到一个函数中(见下文)。如果我理解正确,相同的状态会导致相同的数字序列。所以,如果状态没有改变,我总是得到相同的输出。一种替代方法是在runif函数内生成一个新状态,这样每次调用该函数时,都会调用另一个状态。正如我所听到的那样,这是不可取的,因为函数变慢了。

那么,这样一个函数的最佳实现是什么?我应该在函数内部生成新状态,还是在每次调用函数时生成一个新状态?或者还有另一种方法吗?

__device__ float runif(float a, float b, curandState state)
{
  float myrandf = curand_uniform_double(&state);
  myrandf *=  (b - a + 0.999999);
  myrandf += a;
  return myrandf;
}

1 个答案:

答案 0 :(得分:1)

如何运作

curand_uniform*函数族接受指向curandState对象的指针,以某种方式使用它并对其进行修改,因此当下一次curand_uniform*函数将使用相同的状态对象调用时,您可以拥有期望的随机性。

重要的是: 为了获得有意义的结果,您需要curandState更改回来

错误的方式1

现在您按值传递curandState,因此在内核返回后状态更改将丢失。甚至没有提到复制时不必要的浪费时间。

错误的方式2

在内核中创建和初始化一个新的本地状态不仅会破坏性能(并且不会使用任何CUDA),但会给你错误的分发。

正确的方式

在您链接的示例代码中,curandState由指针传递,以确保保存修改(此指针指向的位置)。

通常,您希望在程序中分配和初始化一次随机状态数组(在启动任何需要RNG的内核之前)。然后,为了生成一些数字,您可以从内核访问此数组,索引基于线程ID。需要多个(多个)状态来避免数据争用(每个并发运行curand_uniform*函数至少有一个状态。)

这样可以避免副本和状态初始化的性能成本,并获得完美的分发。

有关模式信息和示例代码,请参阅cuRand documentation