我想通过简要概述 2015 年的最新技术来补充 Angry Shoe 和 peterchen 的出色回答:
一些不错的选择
randutils
该randutils
库(演示文稿)是一个有趣的新奇事物,提供了一个简单的界面和(声明的)强大的随机功能。它的缺点是它增加了对您的项目的依赖,而且它是新的,还没有经过广泛的测试。无论如何,免费(MIT 许可)和仅标题,我认为值得一试。
最小样本:模具辊
#include <iostream>
#include "randutils.hpp"
int main() {
randutils::mt19937_rng rng;
std::cout << rng.uniform(1,6) << "\n";
}
即使对库不感兴趣,网站 ( http://www.pcg-random.org/ ) 也提供了许多关于随机数生成主题的有趣文章,特别是 C++ 库。
Boost.Random
Boost.Random
(documentation)是启发C++11
's的库<random>
,与他共享大部分界面。虽然理论上也是一个外部依赖,Boost
但目前已经处于“准标准”库的状态,其Random
模块可以被视为高质量随机数生成的经典选择。就解决方案而言,它具有两个优点C++11
:
- 它更便携,只需要对 C++03 的编译器支持
- 它
random_device
使用系统特定的方法来提供高质量的播种
唯一的小缺陷是提供的模块random_device
不是仅标头,必须编译和链接boost_random
。
最小样本:模具辊
#include <iostream>
#include <boost/random.hpp>
#include <boost/nondet_random.hpp>
int main() {
boost::random::random_device rand_dev;
boost::random::mt19937 generator(rand_dev());
boost::random::uniform_int_distribution<> distr(1, 6);
std::cout << distr(generator) << '\n';
}
虽然最小样本可以很好地工作,但实际程序应该使用一对改进:
- make
mt19937
a thread_local
:生成器非常丰满(> 2 KB),最好不要分配在堆栈上
mt19937
具有多个整数的种子:Mersenne Twister 的状态很大,可以在初始化期间利用更多的熵
一些不太好的选择
C++11 库
虽然是最惯用的解决方案,但该<random>
库并没有提供太多以换取其接口的复杂性,即使是基本需求也是如此。缺陷在于std::random_device
:标准不要求其输出的任何最低质量(只要entropy()
返回0
),并且截至 2015 年,MinGW(不是最常用的编译器,但几乎不是一个深奥的选择)将始终打印4
在最低限度的样本上。
最小样本:模具辊
#include <iostream>
#include <random>
int main() {
std::random_device rand_dev;
std::mt19937 generator(rand_dev());
std::uniform_int_distribution<int> distr(1, 6);
std::cout << distr(generator) << '\n';
}
如果实现不烂,则此解决方案应等效于 Boost 解决方案,并且适用相同的建议。
戈多的解决方案
最小样本:模具辊
#include <iostream>
#include <random>
int main() {
std::cout << std::randint(1,6);
}
这是一个简单、有效和简洁的解决方案。唯一的缺陷,编译需要一段时间——大约两年,前提是C++17按时发布,实验randint
功能通过新标准。也许到那个时候,对播种质量的保证也会有所改善。
最小样本:模具辊
#include <cstdlib>
#include <ctime>
#include <iostream>
int main() {
std::srand(std::time(nullptr));
std::cout << (std::rand() % 6 + 1);
}
旧的 C 解决方案被认为是有害的,并且有充分的理由(请参阅此处的其他答案或此详细分析)。尽管如此,它还是有它的优点:简单、便携、快速和诚实,从某种意义上说,众所周知,一个人得到的随机数并不像样,因此人们不会试图将它们用于严肃的目的。
会计巨魔解决方案
最小样本:模具辊
#include <iostream>
int main() {
std::cout << 9; // http://dilbert.com/strip/2001-10-25
}
虽然 9 对于普通掷骰子来说有点不寻常,但人们不得不佩服这个解决方案中优良品质的完美结合,它设法成为最快、最简单、最易于缓存和最便携的解决方案。通过用 4 代替 9,可以得到任何类型的龙与地下城死亡的完美生成器,同时仍然避免包含符号的值 1、2 和 3。唯一的小缺陷是,由于呆伯特会计巨魔的坏脾气,该程序实际上会产生未定义的行为。