生成浮点随机数值(包括负数)

4

如何在C语言中生成浮点随机数?(包括负数


4
你目前有什么进展? - AndersK
我刚刚生成了从0到x的值...没有负数。 - Zany
3
你想要C语言还是C++语言的答案?它们可能会非常不同。请删除不相关的标签。 - Nicola Musatti
1
你说得对,我需要一个 C 语言的答案!我还调整了标签! - Zany
@Zany-Present 你能展示一下你已经完成的工作吗?不要只是发布问题而没有展示你之前尝试过什么。把这当做一个建议。 - Gouse Shaik
好的,对不起。但我没有发布我所做的内容,因为它只是一个简单的rand()...不过,谢谢你的建议,我会更加小心。 - Zany
8个回答

3

一般来说,要从任意分布中生成随机数,首先需要生成均匀分布的随机数,然后将它们传递给累积分布函数的反函数。

例如,假设您想要在区间[-10.0, 10.0]上具有均匀分布的随机数,而您所拥有的只是[0.0, 1.0]范围内的随机数。在[-10.0, 10.0]上的均匀分布的累积分布函数为:

cdf(x) = 0.05 * x + 0.5   for x in [-10.0, 10.0]

这表示生成的随机数小于x的概率。其反义词是
icdf(y) = 20.0 * y - 10.0   for y in [0.0, 1.0]

如果你把x轴和y轴交换,就可以很容易地在纸上得到这个结果。

因此,要获得均匀分布在[-10.0, 10.0]上的随机数,你可以使用以下代码:

#include <stdlib.h>

// Returns uniformly distributed random numbers from [0.0, 1.0].
double uniform0to1Random() {
    double r = random();
    return r / ((double)RAND_MAX + 1);
}

// Returns uniformly distributed random numbers from [-10.0, 10.0].
double myRandom() {
  return 20.0 * uniform0to1Random() - 10.0;
}

事实上,由于已经有很多好的[0.0, 1.0]之间的均匀随机数生成器(例如在boost库中),因此您不需要uniform0to1Random()。
您可以使用该方法通过采样逆累积分布来生成几乎任何概率分布的随机数,如上所示。
有关更多详细信息,请参见http://en.wikipedia.org/wiki/Inverse_transform_sampling

使用srand((signed)time(NULL)); //通常是无符号的 - Talgat

2

编辑:由于问题已经仅限于C语言:

这个页面非常有用:http://www.geekpedia.com/tutorial39_Random-Number-Generation.html


(注:该页面介绍了关于生成随机数的相关技术,供参考)
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

//use this first function to seed the random number generator, 
//call this before any of the other functions 
void initrand() 
{ 
    srand((unsigned)(time(0))); 
} 

//generates a psuedo-random float between 0.0 and 0.999... 
float randfloat() 
{ 
    return rand()/(float(RAND_MAX)+1); 
} 

//generates a psuedo-random float between 0.0 and max 
float randfloat(float max) 
{ 
    return randfloat()*max; 
} 

//generates a psuedo-random float between min and max 
float randfloat(float min, float max) 
{ 
    if (min>max) 
        return randfloat()*(min-max)+max;     
    else 
        return randfloat()*(max-min)+min; 
} 

//generates a psuedo-random double between 0.0 and 0.999... 
double randdouble() 
{ 
    return rand()/(double(RAND_MAX)+1); 
} 

//generates a psuedo-random double between 0.0 and max 
double randdouble(double max) 
{ 
    return randdouble()*max; 
} 

//generates a psuedo-random double between min and max 
double randdouble(double min, double max) 
{ 
    if (min>max) 
        return randdouble()*(min-max)+max;     
    else 
        return randdouble()*(max-min)+min; 
} 

int main()
{
    for (int i=0; i<10; i++)
        printf("%f\n", randdouble(-1,3));
}

输出示例:

2.360751
0.577532
2.132397
2.193760
2.646589
-0.209795
0.340891
2.072918
0.111099
1.215880

(请注意范围:-1..3)

1
@AndrejsCainikovs:标签也不是。C++几乎从来不是纯C。 - sehe
1
不了解C++。在C语言中,当double可以完成相同的任务时,使用float通常是错误的 :-) - pmg

2

以下内容将为您提供一个浮点数,范围在-max/2+max/2之间:

float max = 5000;
float r = max * ((float)rand()/(float)RAND_MAX - 0.5);

它将具有相当奇怪的分布,分子中将有常数,而分母将有函数结果... - glglgl
谢谢,现在它应该看起来更好了。 - Andrejs Cainikovs
非常好 - 但是如果您误用 floatdouble,取决于 RAND_MAX 值,它可能会影响精度。由于不能保证它是2的幂,因此最好在这里也使用 double(尾数52+1而不仅仅是23+1位),或者总体上在这里使用 double 以便不失去任何精度。然而,对于 rand()RAND_MAX 中的任何一个操作数进行转换应该就足够了 - 另一个操作数随之被采纳。 - glglgl

0

Boost是C++。这个问题是关于C的。 - glglgl
3
另一方面,C++标签的存在是具有误导性的。 - Nicola Musatti
真的吗?说真的,这个问题标记了 C++ 标签,所以在投票之前请检查一切! - jopasserat
开箱即用,boost.random 生成随机整数。您没有展示如何使用它来生成随机浮点数。 - Ferruccio
问题是:“如何在C语言中生成浮点随机值?” - glglgl
2
问题在提出后被重新标记了。不幸的是,许多人错误地同时应用 C/C++ 标签,以便将他们的问题展示给更广泛的受众。 - Tim Post

0

您可以使用

rand() / (double)RAND_MAX /* 0 <= random number <= 1 */
rand() / (RAND_MAX + 1.0) /* 0 <= random number < 1 */

要生成一个介于0和1之间的随机数。
然后乘以您所需的范围,并加上初始值。

例如,要获取随机数0 <= X < 4.2

double tmp = rand() / (RAND_MAX + 1.0)
X = tmp * 4.2;

获取随机数 -21.1 <= X <= 37.5

double tmp = rand() / (double)RAND_MAX
X = tmp * (37.5 + 21.1);
X = X - 21.1;

0
GNU科学计算库有一些方法。

http://www.gnu.org/s/gsl/manual/html_node/Random-number-generator-algorithms.html

即使由于许可问题无法使用它,它也应该为您提供一些要在 Google 上搜索的名称。 boost random 库(C++)使用延迟 Fibonacci 和 ranlux 算法来处理双精度和浮点数,因此它们可能是您的另一个选择。(方法不是 boost 库,因为它是 C++) 这些技术通常会给出 0 到 1 范围内的结果。通过使用 R = rmin + v* (rmax-rmin) 公式,其中 v 在 0 到 1 范围内,您将得到 rmin -- rmax 中的 R

-1
我知道的最简单的方法是:
int randNum = rand();
float floatRand = randNum/RAND_MAX;

floatRand是一个在[0,1]范围内的随机浮点数。然而,这种方法的分辨率受到RAND_MAX的限制。

[编辑]: 要获得负值,请生成另一个随机数,如果它大于RAND_MAX/2,则将前一个数乘以(-1)。


谢谢,但我需要算法也能生成负值的可能性... - Zany
1
-1:randNumint 类型;RAND_MAX 是一个 "整数常量表达式"。将第一个除以第二个将始终评估为 0 - pmg

-1

这将生成随机[任何可表示的浮点数]:

#include <stdio.h>

float randfdev(void)
    {
    float tmp;
    int fd = open("/dev/urandom",O_RDONLY);
    read(fd,&tmp,sizeof tmp);
    return tmp;
    }

注意:

  • 没有错误检查
  • 假设使用IEEE浮点格式,但其他格式也应该可以工作
  • 会产生NaN、次正规数、无穷大等结果

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