【发布时间】:2010-09-13 20:49:42
【问题描述】:
我想在 [0.0, 1.0) 范围内获得 均匀分布
如果可能,请让实现使用来自 /dev/urandom 的随机字节。
如果您的解决方案是线程安全的,那就太好了。如果不确定,请注明。
见some solution我看了其他答案后想到的。
【问题讨论】:
标签: c++ multithreading random posix
我想在 [0.0, 1.0) 范围内获得 均匀分布
如果可能,请让实现使用来自 /dev/urandom 的随机字节。
如果您的解决方案是线程安全的,那就太好了。如果不确定,请注明。
见some solution我看了其他答案后想到的。
【问题讨论】:
标签: c++ multithreading random posix
这似乎是个不错的方法:
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 实现。
【讨论】:
简单:假设 IEEE,double 具有 52 位精度。所以生成一个 52 位(或更大)的无符号随机整数(例如通过从 dev/urandom 读取字节),将其转换为双精度并除以 2^(它的位数)。
这给出了数字上的均匀分布(因为一个值在给定范围内的概率与范围成正比)直到第 52 个二进制数字。
复杂:但是,在 [0,1) 范围内有很多 double 值,上面无法生成。具体来说,不会出现 [0,0.5) 范围内的一半值(设置了最低有效位的值)。 [0,0.25) 范围内的四分之三的值(设置了至少 2 位中的任何一个的值)不会发生,等等,一直到只有一个小于 2^-51 的正值是可能的,尽管 double 能够代表这种值的 squillions。所以不能说在指定范围内真正统一到全精度。
当然,我们不想以相等的概率选择其中一个双打,因为这样得到的数字平均会太小。我们仍然需要结果在给定范围内的概率与范围成正比,但在适用于哪些范围方面具有更高的精度。
我认为以下作品。我没有特别研究或测试过这个算法(你可能可以通过没有代码的方式看出),而且我个人不会在没有找到表明它有效的适当参考资料的情况下使用它。但这里是:
我不知道这样的随机替身是否有任何实际用途,请注意。您对随机数的定义应在一定程度上取决于它的用途。但是,如果您可以从其所有 52 个有效位的随机性中受益,那么这实际上可能会有所帮助。
【讨论】:
从文件读取是线程安全的 AFAIK,因此使用 fopen() 从 /dev/urandom 读取将产生“真正随机”的字节。
尽管可能存在潜在的陷阱,但我认为以整数形式访问的任何此类字节集除以该大小的最大整数后,将产生一个介于 0 和 1 之间且大致具有该分布的浮点值。
例如:
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
...
FILE* f = fopen("/dev/urandom", "r");
uint32_t i;
fread(&i, sizeof(i), 1, f); // check return value in real world code!!
fclose(f);
double theRandomValue = i / (double) (UINT32_MAX);
【讨论】:
诀窍是您需要一个 54 位随机发生器来满足您的要求。几行带有联合的代码将这 54 位粘贴在尾数中,然后你就有了你的号码。诀窍不是双浮动,诀窍是您想要的随机化器。
【讨论】:
#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 是你的随机值
【讨论】:
/dev/urandom 不是 POSIX,一般不可用。
在 [0,1) 中均匀生成双精度的标准方法是在 [0,2^N) 范围内生成一个整数并除以 2^N。所以选择你最喜欢的随机数生成器并使用它。对于模拟,我的是Mersenne Twister,因为它非常快,但仍然没有很好的相关性。实际上,它可以为您做到这一点,甚至有一个版本可以为较小的数字提供更高的精度。通常你给它一个种子,这有助于调试的可重复性或向其他人展示你的结果。当然,如果没有指定,你可以让你的代码从 /dev/urandom 中获取一个随机数作为种子。
出于加密目的,您应该改用其中一个标准加密库,例如 openssl),它确实会在可用时使用 /dev/urandom。
至于线程安全,大多数都不会,至少在标准接口中是这样,所以你需要在上面构建一个层,或者只在一个线程中使用它们。那些是线程安全的让你提供他们修改的状态,这样你就可以有效地运行多个非交互随机数生成器,这可能不是你想要的。
【讨论】: