我想通过对 2015 年最新技术的简短概述来补充 Angry Shoe 和 peterchen 的出色回答:
一些不错的选择
randutils
randutils 库(presentation) 是一个有趣的新奇事物,它提供了一个简单的界面和(声明的)强大的随机功能。它的缺点是它增加了对您的项目的依赖,而且它是新的,还没有经过广泛的测试。无论如何,免费(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 的<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 解决方案被认为是有害的,并且有充分的理由(请参阅此处的其他答案或 this detailed analysis)。尽管如此,它还是有它的优点:简单、便携、快速和诚实,因为众所周知,一个人得到的随机数并不像样,因此人们不会试图将它们用于严肃的目的。
会计巨魔解决方案
最小样本:一个骰子
#include <iostream>
int main() {
std::cout << 9; // http://dilbert.com/strip/2001-10-25
}
虽然 9 对于常规掷骰子来说有点不寻常,但人们不得不佩服这个解决方案中优良品质的完美结合,它设法成为最快、最简单、最易于缓存和最便携的解决方案。通过用 4 代替 9,可以得到任何类型的龙与地下城死亡的完美生成器,同时仍然避免包含符号的值 1、2 和 3。唯一的小缺陷是,由于呆伯特会计巨魔的坏脾气,这个程序实际上会产生未定义的行为。