我想在范围[0.0,1.0)
中获得均匀分布如果可能,请让实现使用 / dev / urandom中的随机字节。
如果您的解决方案线程安全,那也很好。如果您不确定,请说明。
在阅读其他答案后,请参阅some solution。
答案 0 :(得分:3)
简单:假设IEEE,双精度具有52位精度。因此,生成一个52位(或更大)的无符号随机整数(例如,通过从dev / urandom读取字节),将其转换为double并将其除以2 ^(它的位数)。
这给出了数值上均匀的分布(因为值在给定范围内的概率与范围成比例)直到第52个二进制数字。
复杂:但是,上面无法生成的[0,1]范围内有很多双值。具体而言,不能发生[0,0.5]范围内的值的一半(设置了最低有效位的值)。 [0,0.25]范围内的四分之三的值(设置了最少2位的值)不会发生等,一直到只有一个小于2 ^ -51的正值是可能的,尽管双重能够代表这些价值的数字。因此,不能说在指定范围内达到完全精确的真正均匀。
当然我们不想以相同的概率选择其中一个双打,因为那样得到的数字平均来说太小了。我们仍然需要结果在给定范围内的概率与范围成比例,但在适用的范围内具有更高的精度。
我认为以下作品。我没有特别研究或测试过这种算法(你可以通过没有代码的方式来判断),而且如果没有找到适当的引用表明它是有效的,我个人不会使用它。但是这里有:
我不知道对于这样一个随机翻倍是否真的有任何实际用途,请注意。你对随机的定义应该取决于它的用途。但是如果你可以从所有52个有效位中获益,那么这实际上可能会有所帮助。
答案 1 :(得分:3)
这似乎是非常好的方式:
unsigned short int r1, r2, r3;
// let r1, r2 and r3 hold random values
double result = ldexp(r1, -48) + ldexp(r2, -32) + ldexp(r3, -16);
这是基于NetBSD的drand48实现。
答案 2 :(得分:0)
#include <stdlib.h>
printf("%f\n", drand48());
double c;
fd = open("/dev/random", O_RDONLY);
unsigned int a, b;
read(fd, &a, sizeof(a));
read(fd, &b, sizeof(b));
if (a > b)
c = fabs((double)b / (double)a);
else
c = fabs((double)a / (double)b);
c是你的随机值
答案 3 :(得分:0)
从文件中读取是线程安全的AFAIK,因此使用fopen()从/ dev / urandom读取将产生“真正随机”的字节。
虽然可能存在潜在的问题,但是将任何一组这样的字节作为整数访问,除以该大小的最大整数,将产生一个介于0和1之间的浮点值,大约是该分布。
例如:
FILE* f = fopen("/dev/urandom", "r");
int32_t int;
fread(&int, sizeof(int32_t), 1, f);
fclose(f);
double theRandomValue = int / (double) (2 ** 32 - 1);
答案 4 :(得分:0)
诀窍是你需要一个符合你要求的54位随机数发生器。几行代码用一个联合来粘贴尾数中的54位,你有你的号码。诀窍不是双重浮动技巧是你想要的随机发生器。
答案 5 :(得分:0)
/ dev / urandom不是POSIX,通常不可用。
在[0,1]中均匀生成double的标准方法是生成[0,2 ^ N]范围内的整数并除以2 ^ N.因此,选择您最喜欢的随机数生成器并使用它。对于模拟,我的是Mersenne Twister,因为它非常快,但仍然没有很好的相关性。实际上,它可以为你做到这一点,甚至有一个版本可以为较小的数字提供更高的精度。通常,您可以给它一个种子,这有助于重复调试或向其他人展示您的结果。当然,如果没有指定,你可以让代码从/ dev / urandom中获取一个随机数作为种子。
出于加密目的,您应该使用其中一个标准加密库,例如openssl),它们确实会在可用时使用/ dev / urandom。
至于线程安全,大多数都不会,至少使用标准接口,所以你需要在顶层构建一个层,或者只在一个线程中使用它们。线程安全的那些让你提供他们修改的状态,这样你就可以有效地运行多个不相互作用的随机数生成器,这可能不是你想要的。