Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/133.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 从范围生成随机整数_C++_Random - Fatal编程技术网

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()的返回值是完全一致的。使用模将增加偏差
到第一个
(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))