我试图使用/ 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);
答案 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);