【问题标题】:Efficiently Get Random Numbers in Range on GPU在 GPU 上有效地获取范围内的随机数
【发布时间】:2013-06-13 16:43:41
【问题描述】:

给定一个在 [0, 2^64) 范围内均匀分布的随机数生成器,是否有任何有效的方法(在 GPU 上)为一些 k

一些不起作用的解决方案:

// not uniformly distributed in [0, k)
myRand(rng, k) = rng() % k;

// way too much branching to run efficiently on a gpu
myRand(rng, k) =
    uint64_t ret;
    while((ret = rng() & (nextPow2(k)-1)) >= k);
    return ret;

// only 53 bits of random data, not 64. Also I
// have no idea how to reason about how "uniform"
// this distribution is.
myRand(doubleRng, k) =
    double r = doubleRng(); // generates a random number in [0, 1)
    return (uint64_t)floor(r*k);

如果差异足够小(例如,在 1/2^64 以内),我愿意妥协不均匀性。

【问题讨论】:

  • @isti_spl 我不是在寻找二进制向量。我正在寻找 [0, k) 范围内的数字。
  • 如果你有一个提供统一随机分布的 rng(n)。在 [0, n-1] 中,那么 rng(n)%k 不是均匀分布的?你需要它们有多“统一”?也许运行一些测试来查看结果分布?
  • 不是。考虑一下你有一个 2 位 RNG 并且你需要一个在 [0, 3) 范围内的数字的情况。使用 64 位 RNG 会遇到同样的危险。

标签: random cuda opencl gpgpu


【解决方案1】:

只有两种选择:进行模数(或浮点数)并解决非均匀性,或使用循环进行拒绝采样。真的没有第三种选择。哪个更好取决于您的应用程序。

如果您的 k 通常非常小(例如,您正在洗牌,因此 k 大约为 100),那么非均匀性非常小它可能没问题,即使是 32 位。在 64 位时,数百万级的 k 仍然会给您带来非常小的不均匀性。不,它不会是 1/2^64 的数量级,但我无法想象在现实世界的应用程序中,1/2^20 数量级的不均匀性是显而易见的。当我为我的 RNG 库编写测试套件时,我故意针对已知的错误 mod 实现运行它,即使是 32 位也很难检测到错误。

如果你真的必须完全统一,那么你只需要抽样和拒绝。这可以很快完成,您甚至可以摆脱除法(计算拒绝循环之外的nextPow2()——这就是我在ojrandlib 中的做法)。仅供参考,做下一个二次幂掩码的最快方法是:

mask = k - 1;
mask |= mask >> 1;
mask |= mask >> 2;
mask |= mask >> 4;
mask |= mask >> 8;
mask |= mask >> 16;
mask |= mask >> 32;

【讨论】:

  • 我假设一个编译器执行 CSE,而 CPU(关于 GPU 的 idk)往往有一个 bsr 指令,它使 nextPow2 两条指令。无论如何,如果我的 k 一般在 [2^63, 2^64-1) 范围内怎么办?
  • 那么您的拒绝率将达到 50%。
【解决方案2】:

如果您有一个返回 53 位随机数据​​的函数,但您需要 64 位,请调用它两次,将第一次调用的低 32 位用作结果的高 32 位,并将结果的低 32 位第二次调用结果的底部 32 位。如果你原来的功能是统一的,那么这个也是。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-02-06
    • 1970-01-01
    • 2023-04-07
    • 2020-10-23
    • 2012-10-10
    • 2011-12-16
    • 2012-10-30
    相关资源
    最近更新 更多