我需要在指定的时间间隔内生成随机数,[max; min].
此外,随机数应该在区间上均匀分布,而不是位于特定点.
Currenly我正在生成:
for(int i=0; i<6; i++) { DWORD random = rand()%(max-min+1) + min; }
从我的测试中,只有一点产生随机数.
Example min = 3604607; max = 7654607;
随机数生成:
3631594 3609293 3630000 3628441 3636376 3621404
从下面的答案:好的,RAND_MAX是32767.我在C++ Windows平台上.有没有其他方法来生成具有均匀分布的随机数?
rand
是个坏主意你在这里得到的大部分答案都使用了rand
函数和模数运算符.该方法可能无法统一生成数字(取决于范围和值RAND_MAX
),因此不鼓励.
随着C++ 11,其他多种选择也有所增加.其中一个符合您的要求,用于生成范围内的随机数,非常好:std::uniform_int_distribution
.这是一个例子:
const int range_from = 0; const int range_to = 10; std::random_device rand_dev; std::mt19937 generator(rand_dev()); std::uniform_int_distributiondistr(range_from, range_to); std::cout << distr(generator) << '\n';
而这里的运行实例.
该
头提供了无数的其他随机数生成与不同类型的分布,包括伯努利,泊松分布和正常的.
标准提供std::shuffle
,可以使用如下:
std::vectorvec = {4, 8, 15, 16, 23, 42}; std::random_device random_dev; std::mt19937 generator(random_dev()); std::shuffle(vec.begin(), vec.end(), generator);
算法将随机重新排序元素,具有线性复杂性.
如果您无法访问C++ 11 +编译器,另一种方法是使用Boost.Random.它的界面非常类似于C++ 11.
[编辑] 警告:不要rand()
用于统计,模拟,加密或任何严重的事情.
对于一个典型的人来说,匆忙的数字看起来是随机的,这已经足够了.
请参阅@ Jefffrey的回复以获得更好的选项,或者这个加密安全随机数的答案.
通常,高位显示比低位更好的分布,因此为简单目的生成范围的随机数的推荐方法是:
((double) rand() / (RAND_MAX+1)) * (max-min+1) + min
注意:确保RAND_MAX + 1不会溢出(感谢Demi)!
除法在区间[0,1]中生成随机数; 将其"拉伸"到所需的范围.只有当max-min + 1接近RAND_MAX时,你需要一个像Mark Ransom发布的"BigRand()"函数.
这也避免了由于模数导致的一些切片问题,这可能会使您的数字更加恶化.
内置随机数发生器不能保证具有统计模拟所需的质量.数字对人类来说"随机"是可以的,但是对于严肃的应用,你应该采取更好的方法 - 或者至少检查它的属性(均匀分布通常是好的,但值往往是相关的,序列是确定的).Knuth对随机数生成器有一个很好的(如果难以阅读)论文,我最近发现LFSR非常好并且实现起来很简单,因为它的属性对你来说还可以.
我想通过对2015年最新技术的简要概述来补充Angry Shoe和peterchen的优秀答案:
一些不错的选择randutils
该randutils
库(演示)是一个有趣的新颖性,提供一个简单的界面和(声明)强大的随机能力.它的缺点在于它增加了对项目的依赖性,而且新的,它还没有经过广泛的测试.无论如何,免费(麻省理工学院许可证)和仅限标题,我认为值得一试.
最小样品:模具辊
#include#include "randutils.hpp" int main() { randutils::mt19937_rng rng; std::cout << rng.uniform(1,6) << "\n"; }
即使一个人对图书馆不感兴趣,网站(http://www.pcg-random.org/)也会提供许多关于随机数生成主题的有趣文章,特别是C++库.
Boost.Random (文档)是启发C++ 11的库
,与其共享大部分接口.虽然理论上也是外部依赖,但Boost现在已经成为"准标准"库的一种状态,其随机模块可以被视为优质随机数生成的经典选择.它具有两个与C++ 11解决方案相关的优点:
它更易于移植,只需要编译器支持C++ 03
它random_device
使用系统特定的方法来提供高质量的播种
唯一的小缺陷是模块产品random_device
不是仅仅头文件,必须编译和链接boost_random
.
最小样品:模具辊
#include#include #include 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具有较大的状态,并且在初始化期间可以利用更多的熵
一些不那么好的选择
虽然是最惯用的解决方案,但
即使对于基本需求,图书馆也没有提供太多交换其界面的复杂性.这个安全漏洞是std::random_device
:该标准没有强制要求其输出的任何最小质量(只要entropy()
回报率0
)和截至2015年,MinGW的(不是最常用的编译器,但几乎没有一个esoterical选择)将始终打印4
在最小的样品.
最小样品:模具辊
#include#include int main() { std::random_device rand_dev; std::mt19937 generator(rand_dev()); std::uniform_int_distribution distr(1, 6); std::cout << distr(generator) << '\n'; }
如果实现没有腐烂,这个解决方案应该等同于Boost,并且适用相同的建议.
最小样品:模具辊
#include#include int main() { std::cout << std::randint(1,6); }
这是一个简单,有效和简洁的解决方案.只有缺陷,编译需要一段时间 - 大约两年,提供C++ 17按时发布,实验randint
功能被批准进入新标准.也许到那个时候,播种质量的保证也会提高.
最小样品:模具辊
#include#include #include int main() { std::srand(std::time(nullptr)); std::cout << (std::rand() % 6 + 1); }
旧的C解决方案被认为是有害的,并且有充分的理由(请参阅此处的其他答案或此详细分析).尽管如此,它仍然具有以下优点:简单,便携,快速和诚实,从某种意义上说,人们知道随机数很难得到,因此人们不会试图将它们用于严肃的目的.
最小样品:模具辊
#includeint main() { std::cout << 9; // http://dilbert.com/strip/2001-10-25 }
虽然9对于普通模具来说有点不同寻常,但人们不得不钦佩这种解决方案中优质品质的完美结合,它可以成为最快,最简单,最便于缓存和最便携的解决方案.通过替换9与4人得到一个完美的生成任何类型的龙与地下城死亡,同时还避免了符号载货值1,2和3.唯一的小缺点是,由于Dilbert的会计巨魔的坏脾气,这个程序实际上会产生未定义的行为.
如果RAND_MAX为32767,则可以轻松地将位数加倍.
int BigRand() { assert(INT_MAX/(RAND_MAX+1) > RAND_MAX); return rand() * (RAND_MAX+1) + rand(); }
如果你能够,使用Boost.我对他们的随机库运气不错.
uniform_int
应该做你想做的事.
如果您担心随机性而不是速度,则应使用安全的随机数生成方法.有几种方法可以做到这一点......最简单的方法是使用OpenSSL的 随机数生成器.
您也可以使用加密算法(如AES)编写自己的算法.通过选择种子和IV然后不断重新加密加密函数的输出.使用OpenSSL更容易,但不那么有男子气概.
您应该查看特定编译器/环境的RAND_MAX.我想如果rand()产生一个随机的16位数字,你会看到这些结果.(你似乎假设它将是一个32位数字).
我不能保证这是答案,但请发布您的RAND_MAX值,并详细了解您的环境.