我已经看到很多关于这个特定主题的问题,但没有一个对我有任何答案,所以我想问这个问题。
我想在[-1,1]之间生成一个随机数。我怎么能这样做?
答案 0 :(得分:18)
使用-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
个唯一的随机数。
答案 1 :(得分:9)
如果你拥有的只是标准C库,那么其他人的答案是明智的。如果您有POSIX功能,请考虑使用drand48()系列函数。特别是:
#define _XOPEN_SOURCE 600 /* Request non-standard functions */
#include <stdlib.h>
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 =伪随机数发生器)。
答案 2 :(得分:8)
我前面有一个类似的问题,并认为直接生成小数部分可能更有效。我做了一些搜索并遇到了一个有趣的快速浮点rand,它不使用浮点除法或乘法,或者int-&gt; float cast可以用float的内部表示的一些intimate knowledge来完成: / p>
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宽度的任何范围。
答案 3 :(得分:6)
对于初学者,您需要C库函数rand()
。这是在stdlib.h
头文件中,因此您应该输入:
#include <stdlib.h>
靠近代码的开头。 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 <stdlib.h>
srand(time(0);
double r = 1.0 * rand() / (RAND_MAX / 2) - 1;
答案 4 :(得分:3)
虽然在许多情况下接受的答案很好,但它会省去“每隔一个数字”,因为它正在将已离散值的范围扩展2以覆盖[-1,1]间隔。以类似的方式,如果你有一个随机数生成器,可以生成[0,10]的整数,你想生成[0,20],简单地乘以2将跨越范围,但不能覆盖范围(它会遗漏所有奇数)。
它可能有足够的细粒度满足您的需求,但确实有这个缺点,在许多应用中可能具有统计意义(并且有害) - 特别是蒙特卡罗模拟和对初始条件具有敏感依赖性的系统。
能够生成从-1到1的任何可表示的浮点数的方法应该依赖于生成序列a1.a2 a3 a4 a5 ...达到浮点精度的极限,这是唯一的方法能够在范围内生成任何可能的浮动。 (即遵循实数的定义)
答案 5 :(得分:1)
来自“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
答案 6 :(得分:0)
正如其他人已经指出的那样,任何简单地将'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()'调用的方法不会产生非常高质量的伪随机数生成器,但它可以很好地用于许多目的。