1

有没有人有 drand48() 的实现或可以在 OpenCL 内核中工作的等价物?

我一直在通过缓冲区发送在主机上生成的随机数,但如果有任何方法可以做到这一点,我需要在设备上生成随机数。

4

1 回答 1

1

这是一个可以从 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库,我是该库的作者。

于 2019-08-02T10:54:04.007 回答