在C中生成[-1,1]之间的随机数?

时间:2009-10-12 22:09:13

标签: c algorithm random

我已经看到很多关于这个特定主题的问题,但没有一个对我有任何答案,所以我想问这个问题。

我想在[-1,1]之间生成一个随机数。我怎么能这样做?

7 个答案:

答案 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) - 返回0RAND_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()'调用的方法不会产生非常高质量的伪随机数生成器,但它可以很好地用于许多目的。