快速,快速随机整数生成器

Fast, Fast random integer generator

本文关键字:整数 随机 快速      更新时间:2023-10-16

有多种算法,如XorShift,可以非常快速地生成满足一般用途的随机数。不幸的是,我需要生成一个从 [0 到 10] 的随机整数,在我的代码中使用 rand() 函数会导致 ~23% 的速度变慢。

问题:生成从 [0 到 10] 的整数的最快方法是什么?

编辑:基于布兰登评论的信息:

~23%的减速假设你已经把它比作某事。你把它和什么比较了?

> 我正在做 rand() % 10> 5。

也:

  • 在循环外使用srand(time(0));什么都不做。

  • 隔离rand() % 10为 ~19%,因此比较对性能的影响不大。

Xorshift是一个很棒的算法。使用它来生成一个充满随机位的缓冲区。仅仅因为它一次填充缓冲区 32 位,就没有理由必须一次从缓冲区中读取 32 位。既然你想要速度,你就想避免除法(和模组)。唯一的方法是通过拒绝抽样(也是获得完全无偏数字的唯一方法)。

由于您只需要 11 个值(0 到 10),因此每个样本只需要 4 位。每 16 个样本中您将拒绝 5 个,但由于每 32 位有 8 个样本,因此每次 Xorshift 迭代平均有 5.5 个输出值。

因此,从 Xorshift 填充一个大缓冲区,然后将该缓冲区转换为 (0 到 10) 值,如下所示:

for (int b = 0; b < sizeof inbuf; b += 1) {
    uint8_t v = ((uint8_t *)inbuf)[b];
    if ((v & 0x0F) < 10) { *outbuf++ = v & 0x0F; }
    if (((v >> 4) & 0x0F) < 10) { *outbuf++ = ((v >> 4) & 0x0F; }
}

outbuf一个字节数组的大小是inbuf的两倍,它将是大约 11/16 满的。根据需要重新填充两个缓冲区。

您是否尝试过标准的 mersenne twister 实现?以下示例来自 Microsoft 的联机帮助:

#include <random>
#include <iostream>
using namespace std;
int main()
{
    random_device rd;   // non-deterministic generator
    mt19937 gen(rd());  // to seed mersenne twister.
    uniform_int_distribution<> dist(0,10); // distribute results between 1 and 10 inclusive.
    for (int i = 0; i < 5; ++i) {
        cout << dist(gen) << " "; // pass the generator to the distribution.
    }
    cout << endl;
}

上次我使用了松本诚的实现,它比rand()快得多。我没有对它进行基准测试,但我猜标准实现也更快。

SSE2还特别支持随机数生成,可能更快:https://software.intel.com/en-us/articles/fast-random-number-generator-on-the-intel-pentiumr-4-processor