我想用一篇简短的综述来补充
Shoe's和
peterchen的出色答案:
一些好选择
randutils
randutils
库(展示)是一个有趣的新奇事物,提供了一个简单的接口和(声明的)强大的随机能力。它的缺点是需要在你的项目中添加依赖,并且由于它是新的,它还没有经过广泛的测试。不管怎样,由于它是免费的(MIT许可证)并且只需要头文件,我认为值得一试。
最小示例:掷骰子
#include <iostream>
#include "randutils.hpp"
int main() {
randutils::mt19937_rng rng;
std::cout << rng.uniform(1,6) << "\n";
}
即使一个人对图书馆不感兴趣,
该网站也提供了许多有关随机数生成主题和特别是C++库的有趣文章。
Boost.Random
Boost.Random
(文档)是启发了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';
}
虽然最小样本很好地完成了它的工作,但实际程序应该采用一对改进:
- 将
mt19937
设为thread_local
:生成器相当臃肿(超过2KB),最好不要在堆栈上分配
- 使用多个整数来种子化
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;
}
虽然在普通骰子的投掷中得到9有些不寻常,但人们必须钦佩这个解决方案中优秀特质的完美结合。它是最快速、最简单、最缓存友好和最易移植的方案。将9替换为4,就可以获得适用于任何
龙与地下城骰子的完美生成器,同时避免了带有符号的1、2和3。唯一的小缺陷是,由于
Dilbert会计巨魔的暴躁情绪,该程序实际上会引发未定义的行为。
rand()
是均匀的。你使用的是哪个库?cstdlib.h
的rand()
是不均匀的:http://www.cplusplus.com/reference/cstdlib/rand/ - Mike Warren