如何实现随机浮点函数,使其不丢失熵? (PHP)

时间:2010-09-11 15:36:35

标签: php math random

我试图使用/ dev / urandom中的字节来生成随机浮点数。目前我最好的想法是让平台精确地做类似的事情:

$maximumPrecision = strlen('' . 1/3) - 2;

然后在循环中构造一个0-9的字符串$ maximumPrecision告诉我们的次数。例如,如果精度为12,我将生成12个随机数并将它们连接起来。我认为这是一个丑陋的想法。

更新:这有意义吗?

$bytes =getRandomBytes(7); // Just a function that returns random bytes.
$bytes[6] = $bytes[6] & chr(15); // Get rid off the other half
$bytes .= chr(0); // Add a null byte

$parts = unpack('V2', $bytes);

$number = $parts[1] + pow(2.0, 32) * $parts[2];
$number /= pow(2.0, 52);

2 个答案:

答案 0 :(得分:4)

PHP的float类型通常实现为IEEE double。这种格式具有52位精度的尾数,因此原则上它应该能够在[0,1]中生成2 52 不同的均匀数字。

因此,您可以从/ dev / urandom中提取52位,解释为整数,并除以2 52 For example

// assume we have 52 bits of data, little endian.
$bytes = "\x12\x34\x56\x78\x9a\xbc\x0d\x00";
//                                  ^   ^^ 12 bits of padding.

$parts = unpack('V2', $bytes);

$theNumber = $parts[1] + pow(2.0, 32) * $parts[2];  // <-- this is precise.
$theNumber /= pow(2.0, 52);                         // <-- this is precise.

答案 1 :(得分:1)

这里的问题是IEEE double precision number是根据基数2的指数来定义的:

n = 2^exponent * 1.mantissa

由于你想要一个指数-1,并且没有n这样的整数2^n = 0.1,它就会变得复杂。

这会产生一个介于1和2之间的数字。你可以减去1,但如果你这样做,你会失去很少的熵(KennyTM的答案会产生一个在这个范围内的数字,但是,使用全部entropy - 这个答案试图直接创建表示法:

$source = fopen("/dev/urandom", "rb");

//build big-endian double
//take only 32 bits because of 32-bit platforms
$byte_batch_1 = fread($source, 4); //32-bit
$byte_batch_2 = fread($source, 4); //32-bit, we only need 20

$offset = (1 << 10) -1;

$first_word = unpack("N", $byte_batch_2);
$first_word = reset($first_word);
$first_word &= 0xFFFFF; //leave only 20 lower bits
$first_word |= $offset << 20;

$str = pack("N", $first_word) . $byte_batch_1;

//convert to little endian if necessary
if (pack('s', 1) == "\x01\x00") { //little-endian
    $str = strrev($str);
}

$float = unpack("d", $str);
$float = reset($float);