在C++中生成随机数的计算成本有多高

How computationally expensive is generating a random number in C++?

本文关键字:计算 随机数 C++      更新时间:2023-10-16

我正在考虑的方法是从范围生成随机整数的答案。

#include <random>
std::random_device rd;     // only used once to initialise (seed) engine
std::mt19937 rng(rd());    // random-number engine used (Mersenne-Twister in this case)
std::uniform_int_distribution<int> uni(min,max); // guaranteed unbiased
auto random_integer = uni(rng);

我也愿意对srand(time(NULL))使用rand()方法。

这些方法有多昂贵?一个比另一个快得多吗?

性能在很大程度上取决于您使用的生成器(这又在很大程度上取决于您所需数字的质量)。

例如,std::mt19937std::random_device得多,但它会产生伪随机数。如果您不需要加密安全的随机数,这对于大多数目的来说都很好。但即使你这样做了,random_device也可以在我的机器上以大约 50 MB/秒的速度产生原始熵——你真正需要多少随机性?(如果需要,mt19937生成的数量级比这多几个数量级)。

避免rand()。它只是具有非常差的特性和非常低的周期。

另见兰德被认为是有害的。

我可以写性能取决于实现和硬件,但它既正确又无用。 性能的一个例子会更有用。

戴尔Latitude E7240笔记本电脑(2013),Linux,g++ 4.8.4和-O3标志:

#include <cstdlib>
#include <iostream>
int main(int argc, const char** argv) {
    const bool bPlain = (argv[1][0] == '-');
    if (bPlain)
        argv++;
    int n = atoi(argv[1]);
    int sum = 0;
    if (bPlain)
        for (int i=0; i<n; i++)
            sum |= i;
    else
        for (int i=0; i<n; i++)
            sum |= rand();
    // To prevent the compiler from optimizing away the loop
    if (sum == 0)
        std::cout << sum << std::endl;
}
[~/CPP] time ./randbm 1000000000
9.049u 0.000s 0:09.05 99.8%    0+0k 0+0io 0pf+0w
[~/CPP] time ./randbm 1000000000
9.059u 0.000s 0:09.06 99.8%    0+0k 0+0io 0pf+0w
[~/CPP] time ./randbm 1000000000
9.040u 0.008s 0:09.05 99.8%    0+0k 0+0io 0pf+0w
[~/CPP] time ./randbm - 1000000000
0.192u 0.000s 0:00.20 95.0%    0+0k 0+0io 0pf+0w
[~/CPP] time ./randbm - 1000000000
0.172u 0.000s 0:00.18 94.4%    0+0k 0+0io 0pf+0w
[~/CPP] time ./randbm - 1000000000
0.185u 0.004s 0:00.20 90.0%    0+0k 0+0io 0pf+0w

因此,在这种特殊情况下,对 rand() 的一次调用大约需要 9 纳秒,而一次循环迭代大约需要 0.2 纳秒

使用random速度较慢。添加#include <random>并将代码的相关部分替换为:

std::random_device rd;     // only used once to initialise (seed) engine
std::mt19937 rng(rd());    // random-number engine used (Mersenne-Twister in this case)
std::uniform_int_distribution<int> uni(0, 1048575);
if (bPlain)
    for (int i=0; i<n; i++)
        sum |= i;
else
    for (int i=0; i<n; i++)
        sum |= uni(rng);
我们

得到(注意我们运行 108 次,而不是 109):

[~/CPP] time ./randbm2 100000000
2.478u 0.003s 0:02.49 99.1%    0+0k 0+0io 0pf+0w
[~/CPP] time ./randbm2 100000000
2.471u 0.004s 0:02.47 100.0%    0+0k 0+0io 0pf+0w
[~/CPP] time ./randbm2 100000000
2.445u 0.007s 0:02.48 98.3%    0+0k 0+0io 0pf+0w
[~/CPP] time ./randbm2 100000000
2.497u 0.004s 0:02.50 99.6%    0+0k 0+0io 0pf+0w
[~/CPP] time ./randbm2 100000000
2.482u 0.011s 0:02.49 100.0%    0+0k 0+0io 0pf+0w

以这种方式生成随机数大约需要 25 纳秒。 然而,unirand()不同,也把数字插入到区间中。

额外的工作重要吗?不。例如,如果您这样做

sum |= (rand() % 1048576);
时间从 9 纳秒

增加到 9.5 纳秒。 如果数字不是 2 的幂,例如

sum |= (rand() % 1000000);

这需要 10 纳秒。 将数字插入区间的其他合理方法需要大致相同的时间。

因此,对于一种特定的配置,rand()本身大约需要 9 纳秒; 加上将随机数插入间隔,大约需要 9.5-10 纳秒; std::mt19937 uniform_int_distribution<int>大约需要 25 纳秒

我希望你不是那些将纳秒与微秒混淆的人之一!