如何在 PHP 中生成 0 到 1 之间的随机浮点数?
我正在寻找相当于Java Math.random()
的PHP。
您可以使用标准函数:lcg_value((。
这是 rand(( 文档中给出的另一个函数:
// auxiliary function
// returns random number with flat distribution from 0 to 1
function random_0_1()
{
return (float)rand() / (float)getrandmax();
}
文档中的示例:
function random_float ($min,$max) {
return ($min+lcg_value()*(abs($max-$min)));
}
class SomeHelper
{
/**
* Generate random float number.
*
* @param float|int $min
* @param float|int $max
* @return float
*/
public static function rand($min = 0, $max = 1)
{
return ($min + ($max - $min) * (mt_rand() / mt_getrandmax()));
}
}
rand(0,1000)/1000 returns:
0.348 0.716 0.251 0.459 0.893 0.867 0.058 0.955 0.644 0.246 0.292
或者,如果您希望小数点后有更多数字,请使用更大的数字
更新:忘记这个答案,它不起作用 php -v> 5.3
怎么样
floatVal('0.'.rand(1, 9));
?
这对我来说非常有效,它不仅适用于 0 - 1,例如在 1.0 - 15.0 之间
floatVal(rand(1, 15).'.'.rand(1, 9));
function mt_rand_float($min, $max, $countZero = '0') {
$countZero = +('1'.$countZero);
$min = floor($min*$countZero);
$max = floor($max*$countZero);
$rand = mt_rand($min, $max) / $countZero;
return $rand;
}
例:
echo mt_rand_float(0, 1);
结果:0.2
echo mt_rand_float(3.2, 3.23, '000');
结果: 3.219
echo mt_rand_float(1, 5, '00');
结果:4.52
echo mt_rand_float(0.56789, 1, '00');
结果:0.69
$random_number = rand(1,10).".".rand(1,9);
PHP 7 的解决方案。在[0,1)
中生成随机数。即包括 0 并排除 1。
function random_float() {
return random_int(0, 2**53-1) / (2**53);
}
感谢评论中的Nommyde
指出我的错误。
>>> number_format((2**53-1)/2**53,100)
=> "0.9999999999999998889776975374843459576368331909179687500000000000000000000000000000000000000000000000"
>>> number_format((2**53)/(2**53+1),100)
=> "1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
function frand($min, $max, $decimals = 0) {
$scale = pow(10, $decimals);
return mt_rand($min * $scale, $max * $scale) / $scale;
}
echo "frand(0, 10, 2) = " . frand(0, 10, 2) . "'n";
此问题要求一个介于 0 到 1 之间的值。对于大多数数学目的,这通常是无效的,尽管在尽可能小的程度上。按照惯例,标准分布是 0>= N <1。你应该考虑你是否真的想要包含 1 的东西。
许多心不在焉的事情都有几十亿分之一的异常结果。如果您考虑向后执行操作,这一点变得很明显。
(int)(random_float() * 10)
将返回一个介于 0 到 9 之间的值,每个值的几率相等。如果在十亿分之一的倍数中它可以返回 1,那么它很少会返回 10。
有些人会在事后解决这个问题(决定 10 应该是 9(。将其乘以 2 应该有大约 ~50% 的几率 0 或 1,但也会有 ~0.000000000465% 的几率返回 2,就像 Bender 的梦中一样。
当您想要从零开始的十个值时,将 0 到 1 作为浮点数可能有点像错误地说 0 到 10 而不是 0 到 9 作为整数。在这种情况下,由于可能的浮点值范围很广,那么它更像是不小心说 0 到 1000000000 而不是 0 到 999999999。
对于 64 位,溢出的情况非常罕见,但在这种情况下,一些随机函数在内部是 32 位的,因此发生二十五亿分之一的机会并非不可信。
相反,标准解决方案希望如下所示:
mt_rand() / (getrandmax() + 1)
分布中也可能有通常不显着的小差异,例如在 0 到 9 之间,那么您可能会发现 0 由于精度的原因,比 9 的可能性略高,但这通常是十亿分之一左右,并且不像上述问题那么严重,因为上述问题可能会产生无效的意外越界数字,否则计算将是完美的。
Java的Math.random也永远不会产生1的值。其中一些来自具体解释它的作用是拗口的。它返回一个从 0 到小于 1 的值。这是芝诺的箭,它永远不会达到1。这不是有人会说的。相反,人们倾向于说在 0 到 1 之间或从 0 到 1 之间,但这些都是错误的。
这在某种程度上是错误报告中的一个娱乐来源。例如,任何使用lcg_value而不考虑这一点的PHP代码如果忠实于其文档,可能会出现故障大约几十亿分之一,但这会使忠实地复制变得非常困难。
这种由一个错误关闭是嵌入式设备中通常遇到的"只需将其关闭并再次打开"问题的常见来源之一。
大多数答案都使用mt_rand
。但是,mt_getrandmax()
通常只返回2147483647
。这意味着你只有 31 位信息,而双精度有一个 52 位的尾数,这意味着 0 到 1 之间的数字密度至少为 2^53
。
这种更复杂的方法将为您提供更精细的分布:
function rand_754_01() {
// Generate 64 random bits (8 bytes)
$entropy = openssl_random_pseudo_bytes(8);
// Create a string of 12 '0' bits and 52 '1' bits.
$x = 0x000FFFFFFFFFFFFF;
$first12 = pack("Q", $x);
// Set the first 12 bits to 0 in the random string.
$y = $entropy & $first12;
// Now set the first 12 bits to be 0[exponent], where exponent is randomly chosen between 1 and 1022.
// Here $e has a probability of 0.5 to be 1022, 0.25 to be 1021, etc.
$e = 1022;
while($e > 1) {
if(mt_rand(0,1) == 0) {
break;
} else {
--$e;
}
}
// Pack the exponent properly (add four '0' bits behind it and 49 more in front)
$z = "'0'0'0'0'0'0" . pack("S", $e << 4);
// Now convert to a double.
return unpack("d", $y | $z)[1];
}
请注意,上述代码仅适用于具有 Litte-Endian 字节序和 Intel 样式IEEE754表示形式的 64 位计算机。(x64
兼容的计算机将具有此功能(。不幸的是,PHP 不允许越过 int32
大小的边界进行位移位,因此您必须为 Big-Endian 编写一个单独的函数。
您应该替换此行:
$z = "'0'0'0'0'0'0" . pack("S", $e << 4);
与其大端对应项:
$z = pack("S", $e << 4) . "'0'0'0'0'0'0";
仅当调用函数的次数很多时,差异才很明显:10^9
次或更多。
测试这是否有效
很明显,尾数遵循一个很好的均匀分布近似,但不太明显的是,大量此类分布的总和(每个分布的概率和幅度累积减半(是均匀的。
运行:
function randomNumbers() {
$f = 0.0;
for($i = 0; $i < 1000000; ++$i) {
$f += 'math::rand_754_01();
}
echo $f / 1000000;
}
生成 0.49999928273099
(或接近 0.5 的类似数字(的输出。
我在 PHP.net 上找到了答案
<?php
function randomFloat($min = 0, $max = 1) {
return $min + mt_rand() / mt_getrandmax() * ($max - $min);
}
var_dump(randomFloat());
var_dump(randomFloat(2, 20));
?>
float(0.91601131712832)
float(16.511210331931)
所以你可以做到
randomFloat(0,1);
或简单
mt_rand() / mt_getrandmax() * 1;
:
echo (float)('0.' . rand(0,99999));
可能会正常工作...希望对您有所帮助。