你如何生成一个随机双0和1之间均匀分布从C ++?(How do you generate a ra

2019-06-21 04:49发布

How do you generate a random double uniformly distributed between 0 and 1 from C++?

Of course I can think of some answers, but I'd like to know what the standard practice is, to have:

  • Good standards compliance
  • Good randomness
  • Good speed

(speed is more important than randomness for my application).

Thanks a lot!

PS: In case that matters, my target platforms are Linux and Windows.

Answer 1:

在C ++ 11和C ++ 14我们与很多更好的选择随机头 。 呈现兰特()是有害的 史蒂芬T. Lavavej解释了为什么我们应该避开使用rand()在C ++中赞成的random头和N3924:在C ++ 14劝阻兰特()进一步强化了这一点。

下面的例子是对cppreference现场样本代码的修改版本,并使用标准:: mersenne_twister_engine发动机和所述的std :: uniform_real_distribution这在产生数字[0,1)范围( 见直播 ):

#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 *************************

由于帖子中提到这样的速度是很重要的,然后我们应该考虑的是描述了不同的随机数字引擎( 重点煤矿 )的cppreference部分:

该引擎使用的选择涉及多个权衡*:所述**线性同余发动机是适度快并且具有用于状态的非常小的存储要求。 滞后斐波那契数生成器的速度非常快,即使在没有先进的运算指令的处理器 ,在更大的固态存储的费用,有时不太理想的光谱特性。 Mersenne扭曲较慢且具有更大的状态存储要求 ,但是具有正确的参数具有最期望的光谱特性的最长非重复序列(对于期望在给定的定义)。

所以,如果有一个更快的发电机的愿望或许ranlux24_base或ranlux48_base超过更好的选择mt19937 。

RAND()

如果你不得不使用rand()那么C常见问题解答 ,指导我怎样才能产生浮点随机数? ,为我们提供了类似这样的一个例子为在区间生成[0,1)

#include <stdlib.h>

double randZeroToOne()
{
    return rand() / (RAND_MAX + 1.);
}

并产生从所述范围内的随机数[M,N)

double randMToN(double M, double N)
{
    return M + (rand() / ( RAND_MAX / (N-M) ) ) ;  
}


Answer 2:

一个老同学的解决方案,如:

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

应该满足您的所有标准(便携式,标准和快速)。 显然产生的随机数,必须接种的标准程序是这样的:

srand((unsigned)time(NULL));


Answer 3:

该random_real类从升压随机库是你需要的。



Answer 4:

这里是你会怎么做,如果你正在使用C ++ TR1 。



Answer 5:

如果速度是你最关心的,那么我会简单地去

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


Answer 6:

在C ++ 11标准库包含一个体面框架和一对夫妇维修发电机的,其是用于家庭作业和关断的,袖口使用完全足够。

但是,对于生产级的代码,你应该确切地知道各种发电机的特殊性质是在使用之前,因为他们都有自己的注意事项。 此外,他们没有经过标准测试像TestU01的PRNG,除了如果与豪华大方因素所使用的ranlux发电机。

如果你想稳固,可重复的结果,那么你必须把你自己的发电机。

如果你想可移植性,那么你必须把你自己的发电机。

如果你能受限的便携性生活,那么你可以使用升压,或结合了C ++ 11的框架用自己的发电机(组)。

更多细节 - 包括优良的品质和丰富的链接一个简单而快速生成的代码 - 可以在我的答案类似主题中找到:

  • 通用随机数生成
  • 非常快的均匀分布的随机数发生器

对于专业制服浮点偏离,需要考虑两个问题:

  • 打开与半开闭与范围,即(0,1),[0,1)或[0,1]
  • 从积分变换的方法,浮点(精度,速度)

二者实际上是相同的硬币的两面,作为转换的方法负责的纳入/排除的0和1下面是对半开区间三种不同的方法:

// exact values computed with bc

#define POW2_M32   2.3283064365386962890625e-010
#define POW2_M64   5.421010862427522170037264004349e-020

double random_double_a ()
{
   double lo = random_uint32() * POW2_M64;
   return lo + random_uint32() * POW2_M32;
}

double random_double_b ()
{
   return random_uint64() * POW2_M64;
}

double random_double_c ()
{
   return int64_t(random_uint64()) * POW2_M64 + 0.5;
}

random_uint32()random_uint64()是您的实际功能占位符和通常会被作为模板参数传递)

方法演示如何创建未被过量精度较低值偏压的均匀偏离; 未示出的64位的代码,因为它是简单的,只是涉及掩蔽掉11位。 分布是所有函数的一致,但没有这招会有在该区域越接近0比其他地方更不同的值(更细的网格间距由于变化的ULP)。

方法c展示了如何得到均匀的速度偏离于某些较受欢迎的平台,其中FPU只知道一个符号的64位整型。 你所看到的最常用的方法是B而没有编译器必须产生大量的额外代码引擎盖下保存无符号的语义。

混合和匹配这些原则来创建自己的定制解决方案。

所有这一切都是在尔根Doornik的优秀论文解释高期随机数转换为浮点 。



Answer 7:

首先包括stdlib.h中

#include<stdlib.h>

然后以下可以是一个函数,以产生在C编程语言的范围之间的随机双号。

double randomDouble() {
    double lowerRange = 1.0;
    double upperRange = 10.0;
    return ((double)rand() * (upperRange - lowerRange)) / (double)RAND_MAX + lowerRange;
}

这里RAND_MAX在stdlib.h中定义



Answer 8:

在我看来,有三种方法去这个问题,

1)最简单的方法。

double rand_easy(void)
{       return (double) rand() / (RAND_MAX + 1.0);
}

2)安全的方式(符合标准的)。

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;
}

3)自定义方式。

通过消除rand()我们再也不用担心任何特定版本,这让我们在我们自己实现更大的空间特质。

注意:这里使用的发电机的时期是≅1.8E + 19。

#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);
}

最后说明:快速版本-而写在C -可以适于在C ++中使用作为用于替换使用std::generate_canonical ,并且将用于任何发生器发射具有足够显著比特值工作。

大多数64位发生器利用其全宽的,所以这可能可以无需修改(移动调整)使用。 例如,这可以作为-与std::mt19937_64引擎。



Answer 9:

那么考虑简洁和速度作为主要标准,你可以添加一个小的通用助手这样的: -

  // 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;
  }

随机数生成是一个很好的研究,复杂的和先进的话题。 您可以从其他的答案中提到的那些在这里找到一些简单而有用的算法开: -

永恒Confuzzled



Answer 10:

你可以尝试梅森倍捻机算法。

http://en.wikipedia.org/wiki/Mersenne_twister

它具有良好的混合速度和随机性,以及GPL实现的。



Answer 11:

这是我最后使用了我的需求:

int range_upper_bound = 12345;
int random_number =((double)rand()/(double)range_upper_bound);


Answer 12:

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;
}

不太一样快, double X=((double)rand()/(double)RAND_MAX); ,但具有更好的分布。 该算法提供返回值只有RAND_MAX均匀间隔的选择; 这一个给出RANDMAX ^ 6,因此其分布受的双精度的限制。

如果你想有一个长双只需添加几个迭代。 如果要在一个数[0,1]而不是[0,1)只是使第4行读out = (double)rand()/(RAND_MAX);



Answer 13:

//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;
}

这应该做的伎俩,我用这个维基百科的文章,以帮助建立这个。 我相信这是一样好drand48();



文章来源: How do you generate a random double uniformly distributed between 0 and 1 from C++?
标签: c++ random