在整个范围内均匀生成随机数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在整个范围内均匀生成随机数相关的知识,希望对你有一定的参考价值。

我需要在指定的时间间隔内生成随机数,[max; min]。

此外,随机数应该在区间上均匀分布,而不是位于特定点。

目前我正在生成:

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函数和模数运算符。这种方法may not generate numbers uniformly(它取决于RAND_MAX的范围和价值),因此不鼓励。

C ++ 11和一系列的生成

随着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_distribution<int>  distr(range_from, range_to);

std::cout << distr(generator) << '\n';

here就是一个运行的例子。

Other random generators

<random> header提供了无数其他随机数生成器,具有不同类型的分布,包括Bernoulli,Poisson和normal。

How can I shuffle a container?

该标准提供std::shuffle,可以使用如下:

std::vector<int> vec = {4, 8, 15, 16, 23, 42};

std::random_device random_dev;
std::mt19937       generator(random_dev());

std::shuffle(vec.begin(), vec.end(), generator);

算法将随机重新排序元素,具有线性复杂性。

Boost.Random

如果您无法访问C ++ 11 +编译器,另一种方法是使用Boost.Random。它的界面非常类似于C ++ 11。

另一答案

这不是代码,但这个逻辑可以帮助你。

static double rnd(void)
{
return (1.0/(RAND_MAX+1.0)*((double)(rand())) );
}

static void InitBetterRnd(unsigned int seed)
{
register int i;
srand( seed );
for( i=0; i<POOLSIZE; i++){
pool[i]= rnd();
}
}

 static double rnd0_1(void)
 {  // This function returns a number between 0 and 1
static int i=POOLSIZE-1;
double r;

i = (int)(POOLSIZE*pool[i]);
r=pool[i];
pool[i]=rnd();
return (r);
}
另一答案

只要整个范围小于RAND_MAX,这应该在[low, high)范围内提供均匀分布而不使用浮点数。

uint32_t rand_range_low(uint32_t low, uint32_t high)
{
    uint32_t val;
    // only for 0 < range <= RAND_MAX
    assert(low < high);
    assert(high - low <= RAND_MAX);

    uint32_t range = high-low;
    uint32_t scale = RAND_MAX/range;
    do {
        val = rand();
    } while (val >= scale * range); // since scale is truncated, pick a new val until it's lower than scale*range
    return val/scale + low;
}

对于大于RAND_MAX的值,您需要类似的东西

uint32_t rand_range(uint32_t low, uint32_t high)
{
    assert(high>low);
    uint32_t val;
    uint32_t range = high-low;
    if (range < RAND_MAX)
        return rand_range_low(low, high);
    uint32_t scale = range/RAND_MAX;
    do {
        val = rand() + rand_range(0, scale) * RAND_MAX; // scale the initial range in RAND_MAX steps, then add an offset to get a uniform interval
    } while (val >= range);
    return val + low;
}

这大致是std :: uniform_int_distribution的功能。

另一答案

就其性质而言,随机数的一小部分样本不必均匀分布。毕竟,它们是随机的。我同意,如果一个随机数生成器生成的数字始终显示为分组,那么它可能存在问题。

但请记住,随机性不一定是统一的。

编辑:我添加了“小样本”来澄清。

另一答案

man 3 rand给出的解决方案包括1到10之间的数字:

j = 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0)));

在你的情况下,它将是:

j = min + (int) ((max-min+1) * (rand() / (RAND_MAX + 1.0)));

当然,这并不像其他一些消息所指出的那样是完美的随机性或一致性,但这对于大多数情况来说已经足够了。

另一答案

@Solution ((double) rand() / (RAND_MAX+1)) * (max-min+1) + min

警告:不要忘记由于拉伸和可能的精度错误(即使RAND_MAX足够大),您也只能生成均匀分布的“箱”而不是[min,max]中的所有数字。


@Solution:Bigrand

警告:请注意,这会使位数加倍,但仍然无法生成范围内的所有数字,即,BigRand()不一定会在其范围内生成所有数字。


信息:只要rand()的范围超出你的间隔范围并且rand()是“均匀的”,你的方法(modulo)就是“很好”。最多第一个最大 - 最小数字的误差是1 /(RAND_MAX +1)。

另外,我建议在C ++ 11中切换到新的random packagee,它提供了比rand()更好和更多种类的实现。

另一答案

我刚在互联网上找到了这个。这应该工作:

DWORD random = ((min) + rand()/(RAND_MAX + 1.0) * ((max) - (min) + 1));
另一答案

[编辑]警告:不要使用rand()进行统计,模拟,加密或任何严重的事情。

对于一个典型的人来说,匆忙的数字看起来是随机的,这已经足够了。

有关更好的选项,请参阅@Jefffrey's reply;有关加密安全随机数,请参阅this answer


通常,高位显示比低位更好的分布,因此为简单目的生成范围的随机数的推荐方法是:

((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的优秀答案:

Some good choices

randutils

randutils(presentation)是一个有趣的新奇,提供简单的界面和(声明)强大的随机功能。它的缺点在于它增加了对项目的依赖性,而且新的,它还没有经过广泛的测试。无论如何,免费(麻省理工学院许可证)和仅限标题,我认为值得一试。

最小样品:模具辊

#include <iostream>
#include "randutils.hpp"
int main() {
    randutils::mt19937_rng rng;
    std::cout << rng.uniform(1,6) << "\n";
}

即使一个人对图书馆不感兴趣,网站(http://www.pcg-random.org/)也会提供许多关于随机数生成主题的有趣文章,特别是C ++库。

Boost.Random

Boost.Random (documentation)是启发C ++ 11的<random>的图书馆,与之共享大部分界面。虽然理论上也是外部依赖,但Boost现在已经成为“准标准”库的一种状态,其随机模块可以被视为优质随机数生成的经典选择。它具有两个与C ++ 11解决方案相关的优点:

  • 它更易于移植,只需要编译器支持C ++ 03
  • 它的random_device使用系统特定的方法来提供高质量的播种

唯一的小缺陷是提供random_device的模块不仅仅是标题,需要编译和链接boost_random

最小样品:模具辊

#include <iostream>
#include <boost/random.hpp>
#include <boost/nondet_random.hpp>

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

虽然最小样本可以很好地工作,但真正的程序应该使用一对改进:

  • 使mt19937成为thread_local:发生器非常丰满(> 2 KB),最好不要在堆栈上分配
  • 种子mt19937有一个以上的整数:Mersenne Twister有一个大的状态,可以在初始化期间受益更多的熵

Some not-so-good choices

C ++ 11库

虽然<random>库是最惯用的解决方案,但即使对于基本需求,qacxswpoi库也没有提供太多交换其界面的复杂性。缺陷在std::random_device:标准并没有要求任何最低质量的产品(只要entropy()返回0),并且,从2015年起,MinGW(不是最常用的编译器,但几乎不是一个深奥的选择)将始终打印4最小的样本。

最小样品:模具辊

#include <iostream&

以上是关于在整个范围内均匀生成随机数的主要内容,如果未能解决你的问题,请参考以下文章

扩展随机数

在矩形内(均匀地)生成随机点?

javascript生成规定范围的随机整数

随机数值域拓宽

将随机范围从 1-5 扩展到 1-7

拒绝采样