使用 C++11 随机库生成随机数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19665818/
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
Generate random numbers using C++11 random library
提问by smac89
As the title suggests, I am trying to figure out a way of generating random numbers using the new C++11 <random>
library. I have tried it with this code:
正如标题所暗示的,我试图找出一种使用新的 C++11<random>
库生成随机数的方法。我已经用这个代码试过了:
std::default_random_engine generator;
std::uniform_real_distribution<double> uniform_distance(1, 10.001);
The problem with the code I have is that every time I compile and run it, it always generates the same numbers. So my question is what other functions in the random library can accomplish this while being truly random?
我的代码的问题是每次编译和运行它时,它总是生成相同的数字。所以我的问题是随机库中的其他哪些函数可以在真正随机的同时实现这一点?
For my particular use case, I was trying to get a value within the range [1, 10]
对于我的特定用例,我试图获得范围内的值 [1, 10]
回答by Bill Lynch
Stephan T. Lavavej (stl) from Microsoft did a talk at Going Native about how to use the new C++11 random functions and why not to use rand()
. In it, he included a slide that basically solves your question. I've copied the code from that slide below.
来自微软的 Stephan T. Lavavej (stl) 在 Going Native 上做了一个关于如何使用新的 C++11 随机函数以及为什么不使用rand()
. 在里面,他附上了一张幻灯片,基本上可以解决你的问题。我已经从下面的幻灯片中复制了代码。
You can see his full talk here: http://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful
你可以在这里看到他的完整演讲:http: //channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful
#include <random>
#include <iostream>
int main() {
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_real_distribution<double> dist(1.0, 10.0);
for (int i=0; i<16; ++i)
std::cout << dist(mt) << "\n";
}
We use random_device
once to seed the random number generator named mt
. random_device()
is slower than mt19937
, but it does not need to be seeded because it requests random data from your operating system (which will source from various locations, like RdRandfor example).
我们使用random_device
once 为名为 的随机数生成器播种mt
。random_device()
比 慢mt19937
,但不需要播种,因为它从您的操作系统请求随机数据(这些数据将来自不同位置,例如RdRand)。
Looking at this question / answer, it appears that uniform_real_distribution
returns a number in the range [a, b)
, where you want [a, b]
. To do that, our uniform_real_distibution
should actually look like:
查看此问题/答案,似乎uniform_real_distribution
返回了[a, b)
您想要的范围内的数字[a, b]
。要做到这一点,我们uniform_real_distibution
实际上应该看起来像:
std::uniform_real_distribution<double> dist(1, std::nextafter(10, DBL_MAX));
回答by Ilya Polishchuk
My 'random' library provide a high convenient wrapper around C++11 random classes. You can do almost all things with a simple 'get' method.
我的“随机”库为 C++11 随机类提供了一个非常方便的包装器。您可以使用简单的“get”方法完成几乎所有事情。
Examples:
例子:
Random number in a range
auto val = Random::get(-10, 10); // Integer auto val = Random::get(10.f, -10.f); // Float point
Random boolean
auto val = Random::get<bool>( ) // 50% to generate true auto val = Random::get<bool>( 0.7 ) // 70% to generate true
Random value from a std::initilizer_list
auto val = Random::get( { 1, 3, 5, 7, 9 } ); // val = 1 or 3 or...
Random iterator from iterator range or all container
auto it = Random::get( vec.begin(), vec.end() ); // it = random iterator auto it = Random::get( vec ); // return random iterator
范围内的随机数
auto val = Random::get(-10, 10); // Integer auto val = Random::get(10.f, -10.f); // Float point
随机布尔值
auto val = Random::get<bool>( ) // 50% to generate true auto val = Random::get<bool>( 0.7 ) // 70% to generate true
来自 std::initilizer_list 的随机值
auto val = Random::get( { 1, 3, 5, 7, 9 } ); // val = 1 or 3 or...
来自迭代器范围或所有容器的随机迭代器
auto it = Random::get( vec.begin(), vec.end() ); // it = random iterator auto it = Random::get( vec ); // return random iterator
And even more things ! Check out the github page:
甚至更多的东西!查看github页面:
回答by Ivanovic
I red all the stuff above, about 40 other pages with c++ in it like thisand watched the video from Stephan T. Lavavej "STL"and still wasn't sure how random numbers works in praxis so I took a full Sunday to figure out what its all about and how it works and can be used.
我红上述所有的东西,关于它40个其它页面与类似于C ++这样并观看了由斯蒂芬T. Lavavej“STL”的视频仍然不知道随机数是如何工作的实践,所以我花了整整周日弄清楚它的全部内容以及它的工作原理和使用方式。
In my opinion STL is right about "not using srand anymore" and he explained it well in the video 2. He also recommend to use:
在我看来,STL 关于“不再使用 srand”是正确的,他在视频2 中很好地解释了这一点。他还建议使用:
a) void random_device_uniform()
-- for encrypted generation but slower (from my example)
a) void random_device_uniform()
-- 用于加密生成但速度较慢(来自我的示例)
b) the examples with mt19937
-- faster, ability to create seeds, not encrypted
b) 具有mt19937
-- 更快、能够创建种子、未加密的示例
I pulled out all claimed c++11 books I have access to and found f.e. that german Authors like Breymann (2015) still use a clone of
我拿出了我可以访问的所有声称的 c++11 书籍,并发现像 Breymann(2015)这样的德国作者仍然使用
srand( time( 0 ) );
srand( static_cast<unsigned int>(time(nullptr))); or
srand( static_cast<unsigned int>(time(NULL))); or
just with <random>
instead of <time> and <cstdlib>
#includings - so be careful to learn just from one book :).
只是用<random>
而不是<time> and <cstdlib>
#includes - 所以要小心地从一本书中学习:)。
Meaning - that shouldn't be used since c++11 because:
含义 - 自 c++11 起不应使用,因为:
Programs often need a source of random numbers. Prior to the new standard, both C and C++ relied on a simple C library function named rand. That function produces pseudorandom integers that are uniformly distributed in the range from 0 to a system- dependent maximum value that is at least 32767. The rand function has several problems: Many, if not most, programs need random numbers in a different range from the one produced by rand. Some applications require random floating-point numbers. Some programs need numbers that reflect a nonuniform distribution. Programmers often introduce nonrandomness when they try to transform the range, type, or distribution of the numbers generated by rand. (quote from Lippmans C++ primer fifth edition 2012)
程序通常需要一个随机数源。在新标准之前,C 和 C++ 都依赖于一个名为 rand 的简单 C 库函数。该函数生成伪随机整数,这些整数均匀分布在从 0 到至少为 32767 的系统相关最大值的范围内。 rand 函数有几个问题: 许多(如果不是大多数)程序需要与一种由兰特生产。某些应用程序需要随机浮点数。一些程序需要反映非均匀分布的数字。程序员在尝试转换由 rand 生成的数字的范围、类型或分布时,通常会引入非随机性。(引自 Lippmans C++ 入门第五版 2012)
I finally found a the best explaination out of 20 books in Bjarne Stroustrups newer ones - and he should know his stuff - in "A tour of C++ 2019", "Programming Principles and Practice Using C++ 2016" and "The C++ Programming Language 4th edition 2014" and also some examples in "Lippmans C++ primer fifth edition 2012":
我终于在 Bjarne Stroustrups 新书的 20 本书中找到了最好的解释——他应该知道他的东西——在“C++ 2019 之旅”、“使用 C++ 2016 的编程原则和实践”和“C++ 编程语言第 4 版”中2014”以及“Lippmans C++ 入门第五版 2012”中的一些示例:
And it is really simple because a random number generator consists of two parts:(1) an engine that produces a sequence of random or pseudo-random values. (2) a distribution that maps those values into a mathematical distribution in a range.
它真的很简单,因为随机数生成器由两部分组成:(1) 一个生成随机或伪随机值序列的引擎。(2) 将这些值映射到某个范围内的数学分布的分布。
Despite the opinion of Microsofts STL guy, Bjarne Stroustrups writes:
尽管微软的 STL 家伙有意见,但 Bjarne Stroustrups 写道:
In , the standard library provides random number engines and distributions (§24.7). By default use the default_random_engine , which is chosen for wide applicability and low cost.
在 中,标准库提供随机数引擎和分布(第 24.7 节)。默认情况下使用 default_random_engine ,选择它是为了广泛的适用性和低成本。
The void die_roll()
Example is from Bjarne Stroustrups - good idea generating engine and distribution with using
(more bout that here).
该void die_roll()
例子与比亚Stroustrups -好主意生成引擎和分布using
(更多的回合,在这里)。
To be able to make practical use of the random number generators provided by the standard library in<random>
here some executable code with different examples reduced to the least necessary that hopefully safe time and money for you guys:
为了能够在此处实际使用标准库提供的随机数生成器,将<random>
一些带有不同示例的可执行代码减少到最不需要的代码,希望为你们节省时间和金钱:
#include <random> //random engine, random distribution
#include <iostream> //cout
#include <functional> //to use bind
using namespace std;
void space() //for visibility reasons if you execute the stuff
{
cout << "\n" << endl;
for (int i = 0; i < 20; ++i)
cout << "###";
cout << "\n" << endl;
}
void uniform_default()
{
// uniformly distributed from 0 to 6 inclusive
uniform_int_distribution<size_t> u (0, 6);
default_random_engine e; // generates unsigned random integers
for (size_t i = 0; i < 10; ++i)
// u uses e as a source of numbers
// each call returns a uniformly distributed value in the specified range
cout << u(e) << " ";
}
void random_device_uniform()
{
space();
cout << "random device & uniform_int_distribution" << endl;
random_device engn;
uniform_int_distribution<size_t> dist(1, 6);
for (int i=0; i<10; ++i)
cout << dist(engn) << ' ';
}
void die_roll()
{
space();
cout << "default_random_engine and Uniform_int_distribution" << endl;
using my_engine = default_random_engine;
using my_distribution = uniform_int_distribution<size_t>;
my_engine rd {};
my_distribution one_to_six {1, 6};
auto die = bind(one_to_six,rd); // the default engine for (int i = 0; i<10; ++i)
for (int i = 0; i <10; ++i)
cout << die() << ' ';
}
void uniform_default_int()
{
space();
cout << "uniform default int" << endl;
default_random_engine engn;
uniform_int_distribution<size_t> dist(1, 6);
for (int i = 0; i<10; ++i)
cout << dist(engn) << ' ';
}
void mersenne_twister_engine_seed()
{
space();
cout << "mersenne twister engine with seed 1234" << endl;
//mt19937 dist (1234); //for 32 bit systems
mt19937_64 dist (1234); //for 64 bit systems
for (int i = 0; i<10; ++i)
cout << dist() << ' ';
}
void random_seed_mt19937_2()
{
space();
cout << "mersenne twister split up in two with seed 1234" << endl;
mt19937 dist(1234);
mt19937 engn(dist);
for (int i = 0; i < 10; ++i)
cout << dist() << ' ';
cout << endl;
for (int j = 0; j < 10; ++j)
cout << engn() << ' ';
}
int main()
{
uniform_default();
random_device_uniform();
die_roll();
random_device_uniform();
mersenne_twister_engine_seed();
random_seed_mt19937_2();
return 0;
}
I think that adds it all up and like I said, it took me a bunch of reading and time to destill it to that examples - if you have further stuff about number generation I am happy to hear about that via pm or in the comment section and will add it if necessary or edit this post. Bool
我认为这一切都加起来了,就像我说的那样,我花了大量阅读和时间将其提炼为这些示例-如果您有关于数字生成的更多信息,我很高兴通过 pm 或在评论部分听到相关信息并将在必要时添加它或编辑此帖子。布尔值
回答by Ng?c Khánh Nguy?n
Here is some resource you can read about pseudo-random number generator.
这是您可以阅读的有关伪随机数生成器的一些资源。
https://en.wikipedia.org/wiki/Pseudorandom_number_generator
https://en.wikipedia.org/wiki/Pseudorandom_number_generator
Basically, random numbers in computer need a seed (this number can be the current system time).
基本上,计算机中的随机数需要一个种子(这个数字可以是当前系统时间)。
Replace
代替
std::default_random_engine generator;
By
经过
std::default_random_engine generator(<some seed number>);
回答by Bill Moore
Here's something that I just wrote along those lines::
这是我刚刚按照这些思路写的东西:
#include <random>
#include <chrono>
#include <thread>
using namespace std;
//==============================================================
// RANDOM BACKOFF TIME
//==============================================================
class backoff_time_t {
public:
random_device rd;
mt19937 mt;
uniform_real_distribution<double> dist;
backoff_time_t() : rd{}, mt{rd()}, dist{0.5, 1.5} {}
double rand() {
return dist(mt);
}
};
thread_local backoff_time_t backoff_time;
int main(int argc, char** argv) {
double x1 = backoff_time.rand();
double x2 = backoff_time.rand();
double x3 = backoff_time.rand();
double x4 = backoff_time.rand();
return 0;
}
~
~
回答by Malcolm McLean
You've got two common situations. The first is that you want random numbers and aren't too fussed about the quality or execution speed. In that case, use the following macro
你有两种常见的情况。第一个是你想要随机数并且不太关心质量或执行速度。在这种情况下,请使用以下宏
#define uniform() (rand()/(RAND_MAX + 1.0))
that gives you p in the range 0 to 1 - epsilon (unless RAND_MAX is bigger than the precision of a double, but worry about that when you come to it).
这为您提供了 0 到 1 范围内的 p - epsilon(除非 RAND_MAX 大于 double 的精度,但是当您遇到它时要担心)。
int x = (int) (uniform() * N);
int x = (int) (uniform() * N);
Now gives a random integer on 0 to N -1.
现在给出一个从 0 到 N -1 的随机整数。
If you need other distributions, you have to transform p. Or sometimes it's easier to call uniform() several times.
如果您需要其他分布,则必须转换 p。或者有时多次调用uniform() 会更容易。
If you want repeatable behaviour, seed with a constant, otherwise seed with a call to time().
如果您想要可重复的行为,请使用常量种子,否则使用 time() 调用种子。
Now if you are bothered about quality or run time performance, rewrite uniform(). But otherwise don't touch the code. Always keep uniform() on 0 to 1 minus epsilon. Now you can wrap the C++ random number library to create a better uniform(), but that's a sort of medium-level option. If you are bothered about the characteristics of the RNG, then it's also worth investing a bit of time to understand how the underlying methods work, then provide one. So you've got complete control of the code, and you can guarantee that with the same seed, the sequence will always be exactly the same, regardless of platform or which version of C++ you are linking to.
现在,如果您对质量或运行时性能感到困扰,请重写 uniform()。但否则不要触摸代码。始终将 uniform() 保持在 0 到 1 减去 epsilon。现在您可以包装 C++ 随机数库以创建更好的 uniform(),但这是一种中等级别的选择。如果您对 RNG 的特性感到困扰,那么也值得花一些时间来了解底层方法的工作原理,然后提供一个。因此,您可以完全控制代码,并且可以保证使用相同的种子,序列将始终完全相同,无论您链接到哪个平台或 C++ 的哪个版本。