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

its*_*ode 14 c random algorithm

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

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

Jac*_*cob 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唯一的随机数.

  • eyalm是正确的,它不会在-1和1之间生成所有可能的浮点值.它将生成RAND_MAX不同的(并且RAND_MAX通常为65535,因此对于特定应用程序可能不够).但是,出于许多目的,这是足够连续的. (4认同)
  • @rmeador:所有可能的浮点值的集合不是均匀分布的.例如,如果最小(正)浮点数是10 ^ -37,则大约一半可能的浮点值位于 - (10 ^ -18)和10 ^ -18之间. (3认同)

Jon*_*ler 10

如果你拥有的只是标准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();
Run Code Online (Sandbox Code Playgroud)

请注意,手册说:

drand48()和erand48()函数应返回非负的,双精度的浮点值,均匀分布在区间[0.0,1.0]上.

如果您严格需要[-1.0,+1.0](而不是[-1.0,+1.0)),那么您将面临一个如何扩展范围的非常微妙的问题.

这些drand48()函数比典型的实现具有更多的随机性rand().但是,如果您需要加密随机性,则这些都不合适; 你需要寻找'密码强PRNG'(PRNG =伪随机数发生器).

  • @ShreevatsaR:错误,如果生成器显示'[0.0,1.0)',则意味着获得结果0.0的机会很小但有限,但是没有机会获得1.0 - 它永远不会出现.你的论点也必须适用于范围的低端.有趣的是,我的'f'将包含范围内的值(-1.0,+ 1.0),而我的'g'将包含范围[-1.0,+ 1.0)中的值. (3认同)
  • @ShreevatsaR:你在一个纯粹的数学世界里玩; 这个网站是关于计算机编程的.你毫无意义地分裂了头发.例如,所有双重值都是固有的有理数; 它们中没有存储超越数,只有(差)近似于超越数. (3认同)
  • 呃,在[-1,1]上的均匀分布在数学上*相同*在[-1,1]上的均匀分布.在两种情况下,获得"1"的概率均为0. (2认同)

Dol*_*hin 8

我前面有一个类似的问题,并认为直接生成小数部分可能更有效.我做了一些搜索并遇到了一个有趣的快速浮点rand,它不使用浮点除法或乘法,或者int-> float cast可以通过对浮点内部表示的一些深入了解来完成:

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 );
}
Run Code Online (Sandbox Code Playgroud)

第一部分从[2 ^ 1,2 ^ 2]生成一个随机浮点数,减去3,你有[-1,1].对于某些应用程序/开发人员而言,这当然可能过于贴心,但这正是我所寻求的.这种机制适用于2宽度范围的任何范围.


Tim*_*Tim 6

首先,您需要C库函数rand().这是在stdlib.h头文件中,所以你应该把:

#include <stdlib.h>
Run Code Online (Sandbox Code Playgroud)

靠近代码的开头.rand()将生成一个介于零之间的随机整数,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;
Run Code Online (Sandbox Code Playgroud)