PHPで0と1の間のランダムフロートを生成するにはどうすればよいですか?
Javaと同等のPHPを探していますMath.random()
。
標準関数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);
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を含むものが必要かどうかを検討する必要があります。
これをぼんやりしている多くのことは、異常な結果の数十億の結果に1つあります。これは、操作を逆方向に実行することを考えると明らかになります。
(int)(random_float() * 10)
各値の確率が等しい0から9までの値を返します。10億回に1回、1を返すことができる場合、代わりに10を返すことはめったにありません。
一部の人々は事後にこれを修正するでしょう(10が9であるべきだと決定するために)。これに2を掛けると、0または1の確率が約50%になりますが、ベンダーの夢のように2を返す確率も約0.000000000465%になります。
0から1を浮動小数点数として言うことは、ゼロから始まる10個の値が必要な場合に、intとして0から9ではなく0から10を誤って言うことに少し似ているかもしれません。この場合、可能なフロート値の範囲が広いため、誤って0から999999999ではなく0から1000000000と言っているようなものです。
64ビットの場合、オーバーフローすることは非常にまれですが、この場合、一部のランダム関数は内部で32ビットであるため、25億分の1の確率で発生する可能性があります。
代わりに、標準ソリューションは次のようになります。
mt_rand() / (getrandmax() + 1)
また、分布には通常はわずかな違いがある場合があります。たとえば、0から9の間では、精度のために0が9よりもわずかに高い可能性がありますが、これは通常10億分の1程度であり、上記の問題ほど深刻ではありません。上記の問題は、そうでなければ完璧な計算に対して、無効な予期しない範囲外の数値を生成する可能性があるためです。
JavaのMath.randomも1の値を生成することはありません。これの一部は、Javaが何をするのかを具体的に説明するのが一口であることに由来しています。0から1未満の値を返します。それはゼノの矢であり、1に達することはありません。これは、誰かが従来言うようなことではありません。代わりに、人々は0から1の間、または0から1の間で言う傾向がありますが、それらは誤りです。
これは、バグレポートの面白さの源です。たとえば、これを考慮せずにlcg_valueを使用するPHPコードは、ドキュメントに忠実である場合、約20億回に1回グリッチが発生する可能性がありますが、忠実に再現することは非常に困難です。
この種の1つのエラーによるオフは、「オフにしてからもう一度オンにする」という一般的な原因の1つです。組み込みデバイスで通常発生する問題。
PHP7のソリューション。で乱数を生成し[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"
ほとんどの回答はを使用してmt_rand
います。ただし、mt_getrandmax()
通常は。のみを返します2147483647
。つまり、情報は31ビットしかないのに対し、doubleには52ビットの仮数があります。つまり、少なくとも2^53
0から1までの数値には密度があります。
このより複雑なアプローチにより、より細かい分布が得られます。
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];
}
上記のコードは、リッテエンディアンのバイトオーダーとIntelスタイルのIEEE754表現を備えた64ビットマシンでのみ機能することに注意してください。(x64
互換性のあるコンピューターにはこれがあります)。残念ながら、PHPはサイズを超えたビットシフトを許可していないためint32
、ビッグエンディアン用に別の関数を作成する必要があります。
次の行を置き換える必要があります。
$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));
おそらくうまくいくでしょう...それがあなたを助けることを願っています。