在C中生成之间的随机数?
我已经看到很多关于这个特定主题的问题,但没有一个对我有任何答案,所以我想问这个问题。
我想在[-1,1]之间生成一个随机数。 我怎么能这样做?
使用-1+2*((float)rand())/RAND_MAX
rand()
生成[0,RAND_MAX]
范围内的整数,因此, ((float)rand())/RAND_MAX
返回[0,1]
的浮点数。 我们通过将它添加到-1
得到[-1,1]
的随机数。
编辑:(添加评论部分的相关部分)
关于这种方法的局限性:
((float)rand())/RAND_MAX
返回一个百分比(从0到1的分数)。 因此,由于-1到1之间的范围是2个整数,我将该分数乘以2,然后将其加到所需的最小数字-1。 这也会告诉您随机数的质量,因为您只有RAND_MAX
唯一的随机数。
如果你拥有的只是标准C库,那么其他人的答案是明智的。 如果您有POSIXfunction,请考虑使用drand48()系列函数。 特别是:
#define _XOPEN_SOURCE 600 /* Request non-standard functions */ #include double f = +1.0 - 2.0 * drand48(); double g = -1.0 + 2.0 * drand48();
请注意,手册说:
drand48()和erand48()函数应返回非负的,双精度的浮点值,均匀分布在区间[0.0,1.0]上。
如果你严格需要[-1.0,+1.0]
(而不是[-1.0,+1.0)
),那么你将面临一个非常微妙的问题,如何扩展范围。
drand48()
函数比rand()
的典型实现提供了更多的随机性。 但是,如果您需要加密随机性,则这些都不合适; 你需要寻找’密码强PRNG’(PRNG =伪随机数发生器)。
我不久前有一个类似的问题,并认为直接生成小数部分可能更有效。 我做了一些搜索并遇到了一个有趣的快速浮点rand,它不使用浮点除法或乘法,或者int-> float cast可以通过对float的内部表示的一些深入了解来完成:
float sfrand( void ) { unsigned int a=(rand()<<16)|rand(); //we use the bottom 23 bits of the int, so one //16 bit rand() won't cut it. a=(a&0x007fffff) | 0x40000000; return( *((float*)&a) - 3.0f ); }
第一部分从[2 ^ 1,2 ^ 2)生成随机浮点数,减去3,你有[-1,1]。 对于某些应用程序/开发人员而言,这当然可能过于贴心,但这正是我所寻求的。 这种机制适用于2宽度范围的任何范围。
首先,你需要C库函数rand()
。 这是在stdlib.h
头文件中,所以你应该把:
#include
靠近代码的开头。 rand()
将生成一个介于0和RAND_MAX
之间的随机整数,因此除以RAND_MAX / 2
将得到一个介于0和2之间的数字。 减去一个,你的目标范围是-1到1。
但是,如果你只是做int n = rand() / (RAND_MAX / 2)
你会发现你没有得到你期望的答案。 这是因为rand()
和RAND_MAX / 2
都是整数,因此使用整数运算。 为了防止这种情况发生,有些人使用浮动投射,但我建议通过乘以1.0
避免强制转换。
您还应该使用srand()
函数为随机数生成器播种。 为了每次获得不同的结果,人们通常通过srand(time(0))
基于时钟时间为发生器播种。
所以,总的来说我们有:
#include srand(time(0); double r = 1.0 * rand() / (RAND_MAX / 2) - 1;
虽然在许多情况下接受的答案很好,但它会省去“每隔一个数字”,因为它将一系列已离散的值扩展为2以覆盖[-1,1]间隔。 以类似的方式,如果你有一个随机数生成器,可以生成[0,10]的整数,你想生成[0,20],简单地乘以2将跨越范围,但不能覆盖范围(它会遗漏所有奇数)。
它可能具有足够精细的颗粒以满足您的需求,但确实存在这种缺点,这在许多应用中可能具有统计意义(并且有害) – 尤其是蒙特卡罗模拟和对初始条件具有敏感依赖性的系统。
能够生成从-1到1(包括-1)的任何可表示的浮点数的方法应该依赖于生成序列a1.a2 a3 a4 a5 …直到浮点精度的极限,这是唯一的方法在该范围内生成任何可能的浮动。 (即遵循实数的定义)
来自“C标准库”
int rand(void)
– 返回0
到RAND_MAX
范围内的伪随机数
RAND_MAX
– rand()
返回的最大值。
所以:
rand()
将返回0
到RAND_MAX
范围内的伪随机数
rand() / RANDMAX
将返回0
到1
范围内的伪随机数
2*( rand() / RANDMAX )
将返回0
到2
范围内的伪随机数
2*( rand() / RANDMAX ) -1
将返回-1
到1
范围内的伪随机数
正如其他人已经指出的那样,任何简单地将’rand()’函数范围从[0,RAND_MAX]转换为所需[-1,+ 1]的尝试都会产生一个随机数生成器,它只能生成一组离散的浮动点值。 对于浮点生成器,在某些应用程序中,这些值的密度可能不足(如果实现定义的RAND_MAX值不够大)。 如果这是一个问题,可以通过使用两个或多个’rand()’调用而不是一个来指数地增加上述密度。
例如,通过将两个连续调用的结果组合到’rand()’,可以在[0,(RAND_MAX + 1)^ 2 – 1]范围内获得伪随机数。
#define RAND_MAX2 ((RAND_MAX + 1ul) * (RAND_MAX + 1) - 1) unsigned long r2 = (unsigned long) rand() * (RAND_MAX + 1) + rand();
然后使用相同的方法将其转换为[-1,+ 1]范围内的浮点数
double dr2 = r2 * 2.0 / RAND_MAX2 - 1;
通过使用这种方法,可以根据需要建立尽可能多的’rand()’调用,当然要注意整数溢出。
作为旁注,这种组合连续’rand()’调用的方法不会产生非常高质量的伪随机数生成器,但它可以很好地用于许多目的。