C++ 从范围生成随机整数
我需要一个函数,它将生成给定范围内的随机整数(包括边界值)。我没有不合理的质量/随机性要求,我有四个要求:C++ 从范围生成随机整数,c++,random,C++,Random,我需要一个函数,它将生成给定范围内的随机整数(包括边界值)。我没有不合理的质量/随机性要求,我有四个要求: 我需要它快点。我的项目需要生成数百万(有时甚至数千万)的随机数,而我当前的生成器功能已被证明是一个瓶颈 我需要它相当统一(使用rand()非常好) 最小-最大范围可以是到 它必须是可播种的 我现在有以下C++代码: output = min + (rand() * (int)(max - min) / RAND_MAX) 问题是,它不是真正统一的——只有当RAND()= RANDMA
- 我需要它快点。我的项目需要生成数百万(有时甚至数千万)的随机数,而我当前的生成器功能已被证明是一个瓶颈
- 我需要它相当统一(使用rand()非常好)
- 最小-最大范围可以是到
- 它必须是可播种的
我现在有以下C++代码:
output = min + (rand() * (int)(max - min) / RAND_MAX)
问题是,它不是真正统一的——只有当RAND()= RANDMAX(VisualC++)为1/32727时,max才返回。这是小范围的主要问题,例如,最后一个值几乎从未返回
所以我拿起笔和纸,想出了以下公式(基于(int)(n+0.5)整数舍入技巧):
但它仍然不能给我均匀的分布。使用10000个样本重复运行,得到的值-1,0的比率为37:50:13。一,
你能推荐更好的配方吗?(甚至是整个伪随机数生成器函数)这里有一个无偏版本,它以
[低、高]
的形式生成数字:
int r;
do {
r = rand();
} while (r < ((unsigned int)(RAND_MAX) + 1) % (high + 1 - low));
return r % (high + 1 - low) + low;
intr;
做{
r=rand();
}而(r<(无符号整数)(RAND_MAX)+1%(高+1-低);;
回报率r%(高+1-低)+低;
如果范围相当小,则没有理由将比较的右侧缓存在do
循环中。如何?boost实现非常易于使用,并且在许多实际应用程序中经过了良好的测试。我自己也在一些学术项目中使用过它,比如人工智能和进化算法
下面是他们的示例,其中他们制作了一个简单的函数来滚动六面模具:
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/variate_generator.hpp>
boost::mt19937 gen;
int roll_die() {
boost::uniform_int<> dist(1, 6);
boost::variate_generator<boost::mt19937&, boost::uniform_int<> > die(gen, dist);
return die();
}
#包括
#包括
#包括
增压:mt19937发电机;
int roll_die(){
boost::统一整数距离(1,6);
boost::变量发生器模具(gen,dist);
回模();
}
哦,这里还有一些关于这台发电机的提示,以防你不相信你应该用它来代替极为劣质的rand()
:
梅森龙卷风是“随机的”
“数字”发电机由Makoto发明
松本拓二,西村拓二,;他们的
该网站包括许多
算法的实现
本质上,梅森捻线机是一种
非常大的线性反馈位移
登记该算法在一个特定的环境下运行
19937位种子,存储在
624 32位无符号的元素数组
整数。值2^19937-1是一个
梅森素数;技术
操纵种子是基于
旧的“扭曲”算法——因此
名字叫“梅森龙卷风”
梅森河迷人的一面
Twister是其使用的二进制代码
操作——与
耗时的乘法——用于
生成数字。算法也同样适用
有很长的一段时间,而且很好
粒度。它既快又快
对非加密应用有效
我建议使用,它非常详细且有很好的文档记录,允许您明确指定所需的分发,并且在非加密场景中,它实际上可以是典型的C库rand实现。这是一种快速的、略优于您的、但仍然不是完全统一的分布式解决方案
output = min + (rand() % static_cast<int>(max - min + 1))
output=min+(rand()%static_cast(max-min+1))
除非范围的大小是2的幂,此方法产生数字,而不管
rand()
的质量如何。要全面测试此方法的质量,请。让我们将问题分为两部分:
- 生成0到(最大-最小)范围内的随机数
n
- 再加上最小值
到第一个
(RAND_MAX+1)%(MAX-min+1)
数字。因此,如果我们能够神奇地将RAND_MAX
更改为RAND_MAX-(RAND_MAX+1)%(MAX-min+1)
,那么就不会再有任何偏差
事实证明,如果我们愿意将伪不确定性引入算法的运行时间,我们可以使用这种直觉。每当rand()返回一个太大的数字时,我们只需请求另一个随机数,直到得到一个足够小的数字
运行时间现在为,预期值为1/p
,其中p
是第一次尝试时获得足够小数值的概率。由于RAND\u MAX-(RAND\u MAX+1)%(MAX-min+1)
始终小于(RAND\u MAX+1)/2
,
我们知道p>1/2
,因此预期的迭代次数总是少于两次
适用于任何范围。使用此技术,在标准CPU上,在不到一秒钟的时间内,应该可以生成数千万个随机数
编辑:
尽管上述理论在技术上是正确的,但迪西蒙的答案在实践中可能更有用。你不应该自己实现这些东西。我见过很多拒绝采样的实现,通常很难判断它是否正确
int RandU(int nMin, int nMax)
{
return nMin + (int)((double)rand() / (RAND_MAX+1) * (nMax-nMin+1));
}
这是32768个整数到(nMax nMin+1)个整数的映射。如果(nMax nMin+1)很小(如您的要求),那么映射将非常好。但是请注意,如果(nMax nMin+1)较大,则映射将不起作用(例如,您不能以相同的概率将32768个值映射为30000个值)。如果需要这样的范围-您应该使用32位或64位随机源,而不是15位rand(),或者忽略超出范围的rand()结果。如果您的编译器支持C++0x,并且您可以选择使用它,那么新的标准
头很可能满足您的需要。它具有高质量的统一的内部分布,将
#include <iostream>
#include <random>
#include <chrono>
int main()
{
typedef std::chrono::high_resolution_clock Clock;
typedef std::chrono::duration<double> sec;
Clock::time_point t0 = Clock::now();
const int N = 10000000;
typedef std::minstd_rand G;
G g;
typedef std::uniform_int_distribution<> D;
D d(-57, 365);
int c = 0;
for (int i = 0; i < N; ++i)
c += d(g);
Clock::time_point t1 = Clock::now();
std::cout << N/sec(t1-t0).count() << " random numbers per second.\n";
return c;
}
G g(seed);
typedef std::uniform_int_distribution<long long> D;
typedef std::mt19937 G; // Now using mersenne_twister_engine
min = -57
max = 365
mean = 154.131
x_mean = 154
var = 14931.9
x_var = 14910.7
skew = -0.00197375
x_skew = 0
kurtosis = -1.20129
x_kurtosis = -1.20001
std::floor( ( max - min + 1.0 ) * rand() ) + min;
#include <random>
std::random_device rd; // only used once to initialise (seed) engine
std::mt19937 rng(rd()); // random-number engine used (Mersenne-Twister in this case)
std::uniform_int_distribution<int> uni(min,max); // guaranteed unbiased
auto random_integer = uni(rng);
int num = (int) rand() % (max - min) + min;
//Where rand() returns a random number between 0.0 and 1.0
int randNum = rand() % (max - min + 1) + min
int randNum = rand() % (max - min) + min + 1
int randNum = rand() % (max - min) + min
int randNum = rand() % (max - min - 1) + min + 1
int randInInterval(int min, int max) {
int intervalLen = max - min + 1;
//now calculate the smallest power of 2 that is >= than `intervalLen`
int ceilingPowerOf2 = pow(2, ceil(log2(intervalLen)));
int randomNumber = rand() % ceilingPowerOf2; //this is "as uniform as rand()"
if (randomNumber < intervalLen)
return min + randomNumber; //ok!
return randInInterval(min, max); //reject sample and try again
}
int n = NUM_DIGIT-1;
while(n >= 0)
{
r[n] = res % b;
res -= r[n];
res /= b;
n--;
}
NUM_DIGIT = floor(log(b,RAND_MAX))