如何从C++;? 如何从C++中生成0到1之间的随机双均匀分布?

如何从C++;? 如何从C++中生成0到1之间的随机双均匀分布?,c++,random,C++,Random,当然,我能想到一些答案,但我想知道标准做法是什么: 良好的标准遵从性 良好的随机性 好速度 (对于我的应用程序来说,速度比随机性更重要) 非常感谢 PS:如果这很重要,我的目标平台是Linux和Windows。一个老式的解决方案,如: double X=((double)rand()/(double)RAND_MAX); 应满足您的所有标准(便携、标准和快速)。 显然,必须对生成的随机数进行播种。标准程序如下: srand((unsigned)time(NULL)); 来自的是您所需要的

当然,我能想到一些答案,但我想知道标准做法是什么:

  • 良好的标准遵从性
  • 良好的随机性
  • 好速度
(对于我的应用程序来说,速度比随机性更重要)

非常感谢


PS:如果这很重要,我的目标平台是Linux和Windows。

一个老式的解决方案,如:

double X=((double)rand()/(double)RAND_MAX);
应满足您的所有标准(便携、标准和快速)。 显然,必须对生成的随机数进行播种。标准程序如下:

srand((unsigned)time(NULL));

来自的是您所需要的。

您可以尝试Mersenne Twister算法


它很好地融合了速度和随机性,并且有一个GPL实现。

如果速度是您最关心的问题,那么我只想使用它

double r = (double)rand() / (double)RAND_MAX;

考虑到简单性和速度是您的主要标准,您可以添加一个小型通用帮助器,如下所示:-

  // C++ rand generates random numbers between 0 and RAND_MAX. This is quite a big range
  // Normally one would want the generated random number within a range to be really
  // useful. So the arguments have default values which can be overridden by the caller
  int nextRandomNum(int low = 0, int high = 100) const {
    int range = (high - low) + 1;
    // this modulo operation does not generate a truly uniformly distributed random number
    // in the span (since in most cases lower numbers are slightly more likely), 
    // but it is generally a good approximation for short spans. Use it if essential
    //int res = ( std::rand() % high + low );
    int res = low + static_cast<int>( ( range * std::rand() / ( RAND_MAX + 1.0) ) );
    return res;
  }
<代码> //C++ + rand在0和随机数之间生成随机数,这是一个相当大的范围。 //通常,人们希望生成的随机数在一个范围内是真实的 //有用。因此,参数具有可由调用方重写的默认值 int nextRandomNum(int low=0,int high=100)常量{ 整数范围=(高-低)+1; //这种模运算不会产生真正均匀分布的随机数 //在跨度内(因为在大多数情况下,较低的数字更可能出现), //但对于短跨度来说,它通常是一个很好的近似值。如果必要,可以使用它 //int res=(标准::兰德()%高+低); int res=low+static_cast((范围*std::rand()/(rand_MAX+1.0)); 返回res; } 随机数生成是一个研究得很好、很复杂且很高级的课题。除了其他答案中提到的算法外,您可以在此处找到一些简单但有用的算法:-


以下是您在使用时的操作方法

没有
double X=((double)rand()/(double)rand_MAX)那么快,但具有更好的分布。该算法只提供RAND_MAX等间距的返回值选择;这一个给出了RANDMAX^6,所以它的分布仅受double的精度限制

如果您想要一个长的双精度,只需添加一些迭代。如果您想在[0,1]中输入一个数字,而不是[0,1],只需将第4行读取为
out=(double)rand()/(rand_MAX);

//返回范围(0.0f,1.0f)内的随机数。
// 0111 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
//见EEEEEEEEEEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
//符号='s'
//指数='e'
//值='v'
双双兰德(){
typedef无符号长uint64;
uint64 ret=0;
对于(int i=0;i<13;i++){

在C++ 11和C++ 14中,RET=((UTIT64)(RAND())16)< P> >。Stephan T. Lavavej的介绍解释了为什么我们不应该在C++中使用<代码> RAND()/<代码>,以支持<代码> Read 标头,并进一步加强这一点。 下面的示例是cppreference站点上示例代码的修改版本,使用引擎和生成
[0,1)
范围()中的数字:

既然帖子提到速度是重要的,那么我们应该考虑描述不同随机数引擎(强调雷)的CP优惠部分:

选择要使用的引擎涉及到许多权衡*: **线性同余引擎速度适中,并且具有非常小的 状态的存储要求。滞后斐波那契发生器 即使在没有高级算术指令的处理器上,速度也非常快 设置,但牺牲了更大的状态存储,有时甚至更少 理想的光谱特性。梅森捻线机速度较慢且 具有更高的状态存储要求,但参数正确 具有最长的非重复序列和最理想的 光谱特性(对于给定的理想定义)

因此,如果有一个更快的发电机的愿望,也许有更好的选择

兰德()

如果您被迫使用
rand()
,那么关于的指南的C FAQ为我们提供了一个类似于此的示例,用于生成间隔
[0,1)


C++11标准库包含一个像样的框架和两个可维护的生成器,这对于家庭作业和即兴使用来说已经足够了

但是,对于生产级代码,在使用之前,您应该确切地知道各种发电机的具体特性,因为它们都有自己的警告。此外,它们都没有通过诸如TestU01之类的PRNG标准测试,除非使用了大量奢侈因素的ranlux发电机

如果你想要可靠的、可重复的结果,那么你必须带上你自己的生成器

如果你想要便携性,那么你必须带上自己的发电机

如果您可以在受限的可移植性下生活,那么您可以将boost或C++11框架与您自己的生成器结合使用

更详细的信息-包括一个简单但快速的生成器的代码,具有卓越的质量和丰富的链接-可以在我对类似主题的回答中找到:

对于专业统一浮点偏差,还有两个问题需要考虑:

  • 打开与半打开与关闭范围,即(0,1),[0,1]或[0,1]
  • 从整数到浮点的转换方法(精度、速度)
两者实际上是同一枚硬币的两面,因为转换方法考虑了0和1的包含/排除
double randDouble()
{
  double out;
  out = (double)rand()/(RAND_MAX + 1); //each iteration produces a number in [0, 1)
  out = (rand() + out)/RAND_MAX;
  out = (rand() + out)/RAND_MAX;
  out = (rand() + out)/RAND_MAX;
  out = (rand() + out)/RAND_MAX;
  out = (rand() + out)/RAND_MAX;

  return out;
}
//Returns a random number in the range (0.0f, 1.0f).
// 0111 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
// seee eeee eeee vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv
// sign     = 's'
// exponent = 'e'
// value    = 'v'
double DoubleRand() {
  typedef unsigned long long uint64;
  uint64 ret = 0;
  for (int i = 0; i < 13; i++) {
     ret |= ((uint64) (rand() % 16) << i * 4);
  }
  if (ret == 0) {
    return rand() % 2 ? 1.0f : 0.0f;
  }
  uint64 retb = ret;
  unsigned int exp = 0x3ff;
  retb = ret | ((uint64) exp << 52);
  double *tmp = (double*) &retb;
  double retval = *tmp;
  while (retval > 1.0f || retval < 0.0f) {
    retval = *(tmp = (double*) &(retb = ret | ((uint64) (exp--) << 52)));
  }
  if (rand() % 2) {
    retval -= 0.5f;
  }
  return retval;
}
#include <iostream>
#include <iomanip>
#include <map>
#include <random>

int main()
{
    std::random_device rd;


    std::mt19937 e2(rd());

    std::uniform_real_distribution<> dist(0, 1);

    std::map<int, int> hist;
    for (int n = 0; n < 10000; ++n) {
        ++hist[std::round(dist(e2))];
    }

    for (auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*') << '\n';
    }
}
0 ************************
1 *************************
#include <stdlib.h>

double randZeroToOne()
{
    return rand() / (RAND_MAX + 1.);
}
double randMToN(double M, double N)
{
    return M + (rand() / ( RAND_MAX / (N-M) ) ) ;  
}
double rand_easy(void)
{       return (double) rand() / (RAND_MAX + 1.0);
}
double rand_safe(void)
{
        double limit = pow(2.0, DBL_MANT_DIG);
        double denom = RAND_MAX + 1.0;
        double denom_to_k = 1.0;
        double numer = 0.0;

        for ( ; denom_to_k < limit; denom_to_k *= denom )
           numer += rand() * denom_to_k;

        double result = numer / denom_to_k;
        if (result == 1.0)
           result -= DBL_EPSILON/2;
        assert(result != 1.0);
        return result;
}
#define RANDMAX (-1ULL)
uint64_t custom_lcg(uint_fast64_t* next)
{       return *next = *next * 2862933555777941757ULL + 3037000493ULL;
}

uint_fast64_t internal_next;
void seed_fast(uint64_t seed)
{       internal_next = seed;
}

double rand_fast(void)
{
#define SHR_BIT (64 - (DBL_MANT_DIG-1))
        union {
            double f; uint64_t i;
        } u;
        u.f = 1.0;
        u.i = u.i | (custom_lcg(&internal_next) >> SHR_BIT);
        return u.f - 1.0;
}
double rand_dist(double min, double max)
{       return rand_fast() * (max - min) + min;
}

double rand_open(void)
{       return rand_dist(DBL_EPSILON, 1.0);
}

double rand_closed(void)
{       return rand_dist(0.0, 1.0 + DBL_EPSILON);
}
#include<stdlib.h>
double randomDouble() {
    double lowerRange = 1.0;
    double upperRange = 10.0;
    return ((double)rand() * (upperRange - lowerRange)) / (double)RAND_MAX + lowerRange;
}
int range_upper_bound = 12345;
int random_number =((double)rand()/(double)range_upper_bound);