在C ++中生成随机数的计算成本如何?

时间:2016-07-17 14:49:35

标签: c++ random time-complexity

我正在考虑的方法来自:https://stackoverflow.com/a/19728404/6571958

#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);

我也愿意将rand()方法与srand(time(NULL))一起使用。

我的问题:这些方法有多贵?一个比另一个快得多吗?

2 个答案:

答案 0 :(得分:4)

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

例如,std::mt19937 std::random_device更快,但产生伪随机数。 如果您不需要加密安全的随机数,这对大多数用途都很好。但即使你这样做,random_device可以在我的机器上以大约50MB /秒的速率产生原始熵 - 你真正需要多少随机性? (mt19937生成的数量级大于需要时的数量级。)

避免使用rand()。它的性质很差,而且周期很短。

另见https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful

答案 1 :(得分:1)

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

E7240笔记本电脑,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 compilier 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);

我们得到(注意我们做1e8次运行,而不是1e9):

[~/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纳秒。但是,与uni不同,rand()也会将数字插入到区间中。

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

sum |= (rand() % 1048576);

时间从9增加到9.5纳秒。如果数字不是2的幂,e。克。

sum |= (rand() % 1000000);

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

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

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