从/dev/urandom获取一个浮点数

4

我可以从/dev/urandom中获取一个随机浮点数值吗?如果我只是简单地使用强制转换,像这样:

int fd = ::open("/dev/urandom", O_RDONLY);
uint32_t n;
read(fd, &n, sizeof(n));
float f = n;

我不确定是否有可移植性的保证,因为我不知道大的n值是否一定可以表示为f? MAXUINT是否保证可以表示为float


1
我非常怀疑你用这种方式生成的数字会是“均匀分布”的,你最好还是使用像drand48()这样的接口来生成随机浮点数。 - sarnold
1
你想要哪个数字范围?通常的方法是像这个问题描述的那样做:https://dev59.com/WXRB5IYBdhLWcg3wN1AQ(使用 /dev/[u]random,就像你建议的那样,可能比调用 rand() 更好,但概念是相同的。)像@sarnold建议的使用 drand48() 似乎也是一个不错的解决方案 - 或许更好。 - mpontillo
1
@Mike:drand48() 的缺点是它使用线性同余算法——适用于科学和大多数游戏,但不适用于密码级别的工作。/dev/urandom 在使用过程中重新填充熵池——但浮点数的格式使我对使用原始位来填充数字的每个字段持怀疑态度... - sarnold
1
@sarnold:变量 n 的值将在范围 0 .. 4294967295 内均匀分布。将其赋值给 f 可能会丢失一些精度,但它仍然应该是相当均匀分布的。是否真的希望在范围 0 .. 4294967295 内使用浮点数值是另一个问题。 - Keith Thompson
1
除非您定义“随机浮点值”的含义,否则无法有意义地回答这个问题。均匀分布还是其他什么?范围是多少? - Keith Thompson
显示剩余5条评论
3个回答

5
您从/dev/urandom获取随机字节,但这些字节不一定会形成a)均匀分布的浮点值或b)任何对象的合法表示。例如,在具有浮点数或整数陷阱表示的平台上,创建的值可能是陷阱表示,您将无法实际使用创建的随机值。
您应该验证库中的std::random_device()实现是否允许访问/dev/urandom(默认情况下或通过取字符串参数,例如:std::random_device("/dev/urandom"))。然后,您就拥有了一个可以与例如std::uniform_real_distribution()一起使用的随机数引擎,以便获得所需的随机数分布。
✓libstdc++默认使用/dev/urandom: ✓libc++也是如此: ✗ Visual Studio的实现甚至没有使用非确定性RNG: ✓自VS2012起,MSDN指出“默认生成的值是不确定的和加密的”,可能通过Windows的加密服务实现。

1
真是个惊喜。GNU libstdc++ 是正确的,LLVM libc++ 也是,但 Visual Studio 完全无法靠近。 - Linuxios
1
哦,拜托了;uint32_t 会有什么陷阱表示呢?将其分配给 float 也不会引起问题。此外,假设 /dev/urandom 是均匀的,那么浮点值将是尽可能均匀的,对吧? - Oliver Charlesworth
@OliCharlesworth uint32_t 不会有陷阱表示,但 int 可能会有。连接均匀分布的字节将产生均匀分布的二进制补码或有符号数,但不会产生均匀分布的 IEEE 754 浮点数。请注意,在 1 和 2 之间以及 2 和 4 之间的 IEEE 754 浮点表示的数量相同。如果您获得一个整数并将其转换为浮点数,则不会出现扭曲,但是您将出现大于某个值的整数将被“舍入”到其他整数值的扭曲。 - bames53
当然,但只有在将位重新解释为“float”时才很重要。 OP仅分配给“float”。 我无法想象在范围[-2 ^ 32,+ 2 ^ 32)内获得更均匀的“float”分布的方法。 - Oliver Charlesworth
"@bames53":「将均匀分布的字节连接起来会产生均匀分布的二进制补码或有符号数,但不会产生均匀分布的IEEE 754浮点数。」实际上,它将产生均匀分布的IEEE 754浮点数,这可能不是任何人想要的! - curiousguy
显示剩余4条评论

0

可以直接将随机字节读入到浮点数中(例如:float f; read(fd, &f, sizeof(f));),假设使用IEEE-754标准,所有位模式都是有效的(尽管有两个无穷大和许多静默NaN和信号NaN)。您可以使用ieee754.hfpclassify.h来确定是否遇到了其中之一。

当然,这是否合理取决于您想要的分布类型。假设使用IEEE-754 float32,您将获得在每个范围内以及整个范围[0, 2-126)的均匀分布,[2-126, 2-125),[2-125, 2-124),...,[2127, 2128)正常值(以及它们的负值)。


这将会给你一个高度倾斜的(因此可能完全无法使用)分布。 - Oliver Charlesworth
@OliCharlesworth它给你一个大致的指数分布。我在答案中解释了这一点。如果你想覆盖所有实数,你还想要什么样的分布? - ephemient
假设使用IEEE-754 float32,您将获得在每个范围内和范围之间的均匀分布,包括[0,2-126)的非规格化数和[2-126,2-125),[2-125,2-124)...... [2127,2128)的规格化数(及其相反数)。还有一些NaN和无穷大,如果您不想要它们,可以进行测试。 - curiousguy
这将会给你一个高度倾斜(因此可能完全无用)的分布,但它是IEEE-754浮点值的均匀分布(可能不是原帖想要的)。无论如何,这个问题定义得不好。当毫无意义的问题受到4个赞时,这个回答怎么能得到1个踩?太疯狂了。 - curiousguy

0

你可以通过将随机整数除以最大整数值来获得一个随机浮点数。

unsigned int RAND_MAX = 0xffffffff; // for 32 bit values
unsigned int random_value = rand_function();
double rand = (double) random_value / (double) RAND_MAX;

那个随机数将在0.0和1.0之间。 如果你想让它在某个范围内,只需这样做:

double x = 1.0; // range start
double y = 3.5; // range end
double range = rand * (y - x) + x; // creates values between 1.0 and 3.5

嗯,RAND_MAX<stdlib.h> 中定义为 int,而不是像这个答案中的 unsigned int - 建议另一个宏名称。通常它的值类似于 0x7fffffff - chux - Reinstate Monica

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