我知道这可能是一个转贴,但我没有找到满意的答案。
我已设法使用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
数组上。
答案 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
。因此,生成的数字不是从整数0
到n
均匀分布的。
但请注意,这都是理论上的解释。我posted some sample code。它只是将整数转换作为代码并构建直方图以查看数字的分布方式。我已经在底部发布了程序的输出,您会看到直方图看起来像从整数0
均匀分布到n-1
。 curand_uniform
返回1.0
的情况似乎非常罕见(不会出现100000
次试用!)。
理论上,如果使用上限函数,您将获得从1
到n
的均匀分布整数,因为如果(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
在您的代码中是多余的。