如何使用 C++11 标准库生成随机数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7217791/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:37:13  来源:igfitidea点击:

How do I generate a random number using the C++11 standard library

c++randomc++11

提问by Bartosz Milewski

The new C++11 Standard has a whole chapter dedicated to random number generators. But how do I perform the simplest, most common task that used to be coded like this, but without resorting to the standard C library:

新的 C++11 标准有一整章专门介绍随机数生成器。但是我如何执行最简单、最常见的任务,这些任务曾经是这样编码的,但又不求助于标准的 C 库:

srand((unsigned int)time(0));
int i = rand();

Are there reasonable defaults for random-number engines, distributions, and seeds that one could use out of the box?

对于可以开箱即用的随机数引擎、分布和种子,是否有合理的默认值?

回答by CB Bailey

You should be able to do something like:

您应该能够执行以下操作:

std::default_random_engine e((unsigned int)time(0));
int i = e();

The quality of the default_random_engineis implementation dependent. You could also use std::min_rand0or std::min_rand.

的质量default_random_engine取决于实现。您也可以使用std::min_rand0std::min_rand

Probably a better way to seed a random engine is with as true a random number as is available from the implementation rather than use time.

可能更好的随机引擎种子方式是使用与实现中可用的随机数一样真实的随机数,而不是使用time

E.g.

例如

std::random_device rd;
std::default_random_engine e( rd() );

回答by mmocny

Unifying and simplifying some of the samples already provided I will summarize to:

统一和简化已经提供的一些示例,我将总结为:

// Good random seed, good engine
auto rnd1 = std::mt19937(std::random_device{}());

// Good random seed, default engine
auto rnd2 = std::default_random_engine(std::random_device{}());

// like rnd1, but force distribution to int32_t range
auto rnd3 = std::bind(std::uniform_int_distribution<int32_t>{}, std::mt19937(std::random_device{}()));

// like rnd3, but force distribution across negative numbers as well
auto rnd4 = std::bind(std::uniform_int_distribution<int32_t>{std::numeric_limits<int32_t>::min(),std::numeric_limits<int32_t>::max()}, std::mt19937(std::random_device{}()));

Then I ran some tests to see what the defaults look like:

然后我进行了一些测试,看看默认值是什么样的:

#include <random>
#include <functional>
#include <limits>
#include <iostream>

template<class Func>
void print_min_mean_max(Func f) {
   typedef decltype(f()) ret_t;
   ret_t min = std::numeric_limits<ret_t>::max(), max = std::numeric_limits<ret_t>::min();
   uint64_t total = 0, count = 10000000;
   for (uint64_t i = 0; i < count; ++i) {
      auto res = f();
      min = std::min(min,res);
      max = std::max(max,res);
      total += res;
   }
   std::cout << "min: " << min << " mean: " << (total/count) << " max: " << max << std::endl;
}

int main() {
   auto rnd1 = std::mt19937(std::random_device{}());
   auto rnd2 = std::default_random_engine(std::random_device{}());

   auto rnd3 = std::bind(std::uniform_int_distribution<int32_t>{}, std::mt19937(std::random_device{}()));
   auto rnd4 = std::bind(std::uniform_int_distribution<int32_t>{std::numeric_limits<int32_t>::min(),std::numeric_limits<int32_t>::max()}, std::mt19937(std::random_device{}()));

   print_min_mean_max(rnd1);
   print_min_mean_max(rnd2);
   print_min_mean_max(rnd3);
   print_min_mean_max(rnd4);
}

Produces the output:

产生输出:

min: 234 mean: 2147328297 max: 4294966759
min: 349 mean: 1073305503 max: 2147483423
min: 601 mean: 1073779123 max: 2147483022
min: -2147481965 mean: 178496 max: 2147482978

So as we can see, mt19937 and default_random_engine have a different default range, so use of uniform_int_distribution is advised.

因此我们可以看到,mt19937 和 default_random_engine 具有不同的默认范围,因此建议使用 uniform_int_distribution。

Also, default uniform_int_distribution is [0, max_int] (non-negative), even when using a signed integer type. Must provide range explicitly if you want full range.

此外,默认的 uniform_int_distribution 是 [0, max_int](非负),即使使用有符号整数类型也是如此。如果您想要全范围,则必须明确提供范围。

Finally, its important to remember thisat times like these.

最后,在这种时候记住这一点很重要

回答by Carl

Here you go. Random doubles in a range:

干得好。范围内的随机加倍:

// For ints
// replace _real_ with _int_, 
// <double> with <int> and use integer constants

#include <random>
#include <iostream>
#include <ctime>
#include <algorithm>
#include <iterator>

int main()
{
    std::default_random_engine rng(std::random_device{}()); 
    std::uniform_real_distribution<double> dist(-100, 100);  //(min, max)

    //get one
    const double random_num = dist(rng);

    //or..
    //print 10 of them, for fun.
    std::generate_n( 
        std::ostream_iterator<double>(std::cout, "\n"), 
        10, 
        [&]{ return dist(rng);} ); 
    return 0;
}

回答by dimitri

I use the following code in my project. 'engine' and 'distribution' can be one of the provided by the library.

我在我的项目中使用以下代码。'engine' 和 'distribution' 可以是库提供的其中之一。

#include <random>
#include <functional>
#include <iostream>
...
std::uniform_int_distribution<unsigned int> unif;
std::random_device rd;
std::mt19937 engine(rd());
std::function<unsigned int()> rnd = std::bind(unif, engine);

std::cout << rnd() << '\n';

回答by David Heffernan

If your existing code was appropriate before the new standard, then it will continue to be. The new random number generators were added for applications which require a higher quality of pseudo-randomness, e.g. stochastic simulation.

如果您现有的代码在新标准之前是合适的,那么它将继续适用。新的随机数生成器被添加到需要更高质量的伪随机性的应用中,例如随机模拟。

回答by Adam Hawes

Random number generation is a difficult problem. There is no truly random way to do it. If you are just generating randomness to seed a game environment then your approach should be fine. rand() has several shortcomings.

随机数生成是一个难题。没有真正随机的方法来做到这一点。如果您只是生成随机性来播种游戏环境,那么您的方法应该没问题。rand() 有几个缺点。

If you are needing randomness to generate encryption keys then you're S.O.L. The best way in that case is to go out to the operating system, which usually has mechanism. On POSIX that's random() (or read from /dev/random if you're so disposed). On Windows you can use the CryptoAPI:

如果您需要随机性来生成加密密钥,那么您就是 SOL 在这种情况下,最好的方法是使用通常具有机制的操作系统。在 POSIX 上,它是 random() (或者如果你愿意的话,可以从 /dev/random 读取)。在 Windows 上,您可以使用 CryptoAPI:

https://www.securecoding.cert.org/confluence/display/seccode/MSC30-C.+Do+not+use+the+rand%28%29+function+for+generating+pseudorandom+numbers

https://www.securecoding.cert.org/confluence/display/seccode/MSC30-C.+Do+not+use+the+rand%28%29+function+for+generating+pseudorandom+numbers

回答by Matt Mahoney

You could use RC4 to generate random bytes. This probably has the properties that you want. It is fast and fairly simple to implement. The sequence is repeatable across all implementations when the seed is known, and completely unpredictable when the seed is not known. http://en.wikipedia.org/wiki/RC4

您可以使用 RC4 生成随机字节。这可能具有您想要的属性。它实现起来很快而且相当简单。当种子已知时,该序列在所有实现中是可重复的,而当种子未知时则完全不可预测。http://en.wikipedia.org/wiki/RC4