使用cuRand从均匀分布生成随机整数的正确方法是什么?

时间:2017-04-25 23:16:35

标签: cuda

我知道这可能是一个转贴,但我没有找到满意的答案。

我已设法使用n从0到curand_uniform范围内的实数生成整数,但我想知道是否有更好的方法来确保数字在统计上均匀分布。< / p>

__global__ void generate_kernel(int n, curandState *state, int *result)
{   int id = blockIdx.x * blockDim.x + threadIdx.x;
    unsigned int x;
    if (id < n)
    {    curandState localState = state[id];            

         float aux = curand_uniform(&localState) * n;
         x = aux ;

         state[id] = localState;
         result[id] = x;
    }
}

那么,我应该使用其他一些东西而不是curand_uniform()的整数部分乘以n吗?顺便说一下,我有n个线程,每个线程都有自己不同的状态和种子。每个线程生成一个值并将其保存在results数组上。

1 个答案:

答案 0 :(得分:0)

你说每个线程都有自己的种子。这意味着每个线程都有自己的一组随机数。因此,使用您的内核,将通过基于线程的实现统一性,并且为了获得统一生成的数字,您将不得不多次调用上述内核。但是,如果您打算只调用此内核一次并期望n均匀分布的值,则每个n个线程应具有相同的种子值,并且不同的序列或偏移值。有关示例代码的详细信息,请查看this article

此外,curand_uniform的返回值还有一些微妙之处。从cuRAND文档§3.1.4开始,它说:

__device__ float
curand_uniform (curandState_t *state)
     

此函数统一返回一系列伪随机浮点数   分布在0.0和1.0之间。它可能会从0.0返回到1.0,其中   包含1.0,排除0.0

您的代码是:

unsigned int x = curand_uniform(&localState) * n;

转换为整数类型会截断为零(link)。因此,从理论上讲,只有当n返回的值为curand_uniform时才会获得1.0(这种情况很少见)。但是,当k, (0 < k < n)返回的值(我将此返回值表示为curand_uniform)为y时,您将获得k/n <= y < (k+1)/n,并且您将获得0 1}}如果0 < y < 1/n。因此,生成的数字不是从整数0n均匀分布的。

但请注意,这都是理论上的解释。我posted some sample code。它只是将整数转换作为代码并构建直方图以查看数字的分布方式。我已经在底部发布了程序的输出,您会看到直方图看起来像从整数0均匀分布到n-1curand_uniform返回1.0的情况似乎非常罕见(不会出现100000次试用!)。

理论上,如果使用上限函数,您将获得从1n 的均匀分布整数,因为如果(k-1)/n < y <= k/n,那么{{1} } ceilf(y * n)将为k

1 <= k <= n

code I posted也涵盖了上述情况。您可以运行它并查看与此类似的结果(在这种情况下为unsigned int x = ceilf(curand_uniform(&localState) * n); ):

n = 10

另请注意,Histogram for the generated random numbers (with casting) 0 : 9993 1 : 9926 2 : 10138 3 : 10131 4 : 9980 5 : 9967 6 : 9979 7 : 10054 8 : 9921 9 : 9911 10 : 0 Histogram for the generated random numbers (with ceiling) 0 : 0 1 : 10036 2 : 10033 3 : 9899 4 : 9952 5 : 9960 6 : 9892 7 : 10167 8 : 9839 9 : 10198 10 : 10024 在您的代码中是多余的。