C++生成一个介于0和100,000之间的随机数。

4

什么是最好的方法呢?我的编译器显示RAND_MAX = 32,767。因此,我很好奇如何在0到100,000之间获得均匀随机生成的值?


3
使用 <random> 头文件。 - chris
7
请参阅std::uniform_int_distribution以及相关内容。 - juanchopanza
5个回答

10

我将把juanchopanza的评论放在答案中。

如果您的编译器提供了它(C++11),请使用<random>头文件。

std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 10000);

std::cout << dis(gen) << std::endl;

1
如果由于任何原因,您不能或不想这样做,请使用具有足够位数的生成器(或将2个调用与移位和或组合),将其掩码到最接近2的幂(在您的情况下为&131071),并拒绝任何大于100,000的值。请注意,这具有非确定性运行时间,但这是获得非偏差分布的唯一直接方法。请勿使用模运算符。 - Damon
@Damon:& 131071 当然是伪装成模运算符 % 131072 的取模运算符,所以说永远不要使用模运算符有点不真诚。当 (rand_max + 1) mod n > 0 时,无论如何取模(任何伪装),都会存在偏差。 - MSalters
@MSalters:虽然在这种情况下,伪装的模运算符实际上并不是模运算符。屏蔽掉一个无偏数的最低N位不会以任何方式使这些位产生偏差。这确实是唯一重要的区别。当然,如果你想从RAND_MAX中获取17位并尝试神奇地拉出15位,那是行不通的(如果你想称之为“偏差”,那就是偏差),但这就是我说需要组合两个随机数的原因,例如rand()|(rand()<<15),以获得足够的随机位。无论你是否移位,随机位都是同样随机的... - Damon
@Damon: 蒙蔽一个无偏数的低位绝对会产生偏差。显然,给定范围为[0,2]的无偏数,将低位蒙蔽后,可能性为2/3得到0。在范围为[0,8]的数字中,模2仍然会产生偏差(0的概率为5/9),但模3不会(所有结果的概率都是1/3)。为什么呢? (8+1)模2 > 0,但(8+1)模3 = 0 - MSalters
@Damon:你为什么要这样假设?标准里面没有保证这一点;最好的情况是RAND_MAX至少为32767。基于"rand()没有问题"的假设进行推断是一个坏主意;我们知道它通常存在问题。 - MSalters
显示剩余2条评论

1

我很久以前在某个网站上找到了下面的函数。作者声称该函数能够提供良好的均匀性。

#define RS_SCALE (1.0 / (1.0 + RAND_MAX))
double drand(void) 
{
    double d;
    do {
       d = (((rand () * RS_SCALE) + rand ()) * RS_SCALE + rand ()) * RS_SCALE;
    } while (d >= 1); /* Round off */
    return(d);
}

如下评论所述,此代码返回的是0到1之间的数字,请将其乘以100000,即 drand()*100000


这返回的是[0, 1),没有回答问题。 - Mihai Maruseac
2
需要注意的是,rand 中没有足够的位数(RAND_MAX 为32k)来处理这种情况。除非您进行一些黑客操作,例如调用 rand 两次并组合输出,否则您的分布将会有“空洞”。 - Damon
1
@Damon 我不明白为什么当RAND_MAX=32k时会出现空洞。如果drand()所产生的分布在范围[0,1)内是均匀的(且在此范围内没有空洞),那么它乘以100000后的范围也将是[0,100000)内均匀且没有空洞,不是吗? - Igor Popov
@IgorPopov:不,FP数学不遵循实际数学规则。在0和1.0之间有有限数量的“double”值,在0和100000.0之间有更多的“double”值。(从数学上讲,这两个集合的大小相等)。根据鸽笼原理,必须有空洞。话虽如此,“double”通常在0和1之间有大约2^62个值(一半的数字是正数,一半的正值在1和无穷大之间)。显然,您需要调用5次“rand()”才能获得超过60位,以避免出现空洞。 - MSalters

1
你应该下载并使用一个严肃的伪随机数生成器,例如 Gnu Scientific Library 中提供的那些。

我们已经有了标准的严肃PRNG(Boost也有一些)。 - chris
1
@chris 最近的C++标准是支持的,但他的编译器不一定支持。 - pjs
嗯,这就是Boost的作用。你几乎可以假设每个C++开发者都有它。 - chris
1
@chris 所以我们都认为他可能会受益于使用一个能够正确完成工作的外部库。他有选择是一件好事。 - pjs
不能使用外部库。这是为了学校项目,如果教授的系统上没有它,我不能在我的电脑上用它。我以前从未需要生成一个大于10,000的随机数。 - Medic3000

-1
我发现的方法是首先包含#include <time.h>,然后你可以写srand(time(NULL));来为随机函数种子赋值。然后你只需要使用这行代码:(rand() % 99999 + 1);。这应该会给你一个在0到100,000之间的随机值。如果需要,你也可以将其分配给一个变量:int myVar = (rand() % 99999 + 1);。希望这有所帮助!(我希望我完全正确。我还在攻读计算机科学学位,仍在学习C++,但我以前做过这个并且它有效。)

rand()函数返回的最大值是RAND_MAX,通常为32,767。 - ClayD

-3

这是你的代码:

100000.0f * ((float)rand() / 32767.0f)

这将生成从0到100000的随机浮点数,但您可以在此处使用任何正数,而不是100000。

更新:

确实(感谢下面psj的评论),我意识到上述内容涵盖了0..100000范围的约1/3。


均匀性在这里取决于 rand(),所以我也不确定;-) - Artur
4
我确定不是这样的。它只能生成范围在[0,100000]内的大约三分之一的整数。 - pjs
这只是将一个随机数进行缩放,你会错过很大一部分的范围。 - The Floating Brain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接