有没有人有 drand48() 的实现或可以在 OpenCL 内核中工作的等价物?
我一直在通过缓冲区发送在主机上生成的随机数,但如果有任何方法可以做到这一点,我需要在设备上生成随机数。
这是一个可以从 OpenCL 内核调用的 OpenCL 设备函数:
uint rng_next(__global ulong *states, uint index) {
/* Assume 32 bits */
uint bits = 32;
/* Get current state */
ulong state = states[index];
/* Update state */
state = (state * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1);
/* Keep new state */
states[index] = state;
/* Return value */
return (uint) (state >> (48 - bits));
}
该states
数组包含每个工作项的 PRNG 状态,索引基本上是 - 但不一定是 - 工作项 ID(您可以使用 获取get_global_id()
)。
该states
数组可以在主机中生成(使用另一个 PRNG)并复制到设备,或者可以使用应用于工作项全局 ID 的某种散列函数在设备中初始化。如果您使用工作项全局 ID 作为初始种子,每个工作项的随机流质量将非常低(由于它们之间的高度相关性)。这是一个内核,用于应用哈希函数来解相关初始种子(请注意,您需要一个主要的初始种子,由主机传递):
__kernel void rng_init(
const ulong main_seed,
__global clo_statetype *seeds) {
/* Get initial seed for this workitem. */
ulong seed = get_global_id(0) + main_seed;
/* Apply basic xor-shift hash, better ones probably exist. */
seed = ((seed >> 16) ^ seed) * 0x45d9f3b;
seed = ((seed >> 16) ^ seed) * 0x45d9f3b;
seed = ((seed >> 16) ^ seed);
/* Update seeds array. */
seeds[get_global_id(0)] = seed;
}
请注意,正如评论中所指出的,drand48 的质量非常低,如果您使用大量工作项,您将在渲染中看到伪影。这篇文章更详细地解释了这一点。
这段代码取自cl_ops库,我是该库的作者。