[PHP] mt_rand関数で特定の値を除外したい場合

mt_rand関数を使って、ランダムな値を作りたいけど、
その中で、一部の値を除外したい時って、
あるじゃないですか。

例えば、1~10の間のランダムな数値を作りたいが、
5だけは出ないようにしたい。とか。

でも、どうやらmt_rand関数には、
そういうオプションはありそうにない。

https://www.php.net/manual/ja/function.mt-rand.php
(「random_intを使いましょう」的な警告は一旦置いときます。)

そういう機能のあるランダム値を返す関数も、
調べても見つからないので、
ちょっと簡単に作ってみました。

<?php

function mt_rand_except( int $min, int $max, int $except ) : int {

    do {
        $num = mt_rand($min, $max);
    } while ($num == $except);

    return $num;
}

print mt_rand_except( 1, 10, 5 );

ただし、これで動作確認しても、
本当に5が除外されてるのかわかりにくいですw

なので、以前作った、
mt_rand関数のばらつきを調べるプログラムを使って、
動作確認してみます。

<?php

$parameter = 10000; // mt_randを実行する回数
$rand_min = 1;      // MIN
$rand_max = 10;     // MAX
$except_num = 5;    // 除外したい数字

$buf = array_pad( array(), $rand_max - $rand_min + 1, 0 ); // 出た数字のカウントを格納する配列

for($i = 1; $i < $parameter; $i++){
    $sample = mt_rand_except( $rand_min, $rand_max, $except_num );
    $buf[$sample - $rand_min]++;
}

function mt_rand_except( int $min, int $max, int $except ) : int {

    do {
        $num = mt_rand($min, $max);
    } while ($num == $except);

    return $num;
}

?>

<!DOCTYPE html>
<head>
    <title>mt_rand test</title>
</head>
<body>

<table border="1">
    <tr>
        <th>No.</th>
        <th>times</th>
        <th>rate</th>
    </tr>

<?php

for($i = $rand_min; $i <= $rand_max; $i++){
    print("<tr align=\"right\"><td>".$i."</td>");
    print("<td>".$buf[$i-$rand_min]."回</td>");
    printf("<td>%.2f%%</td></tr>\n",$buf[$i-$rand_min]/$parameter*100);
}
?>
</table>

</body>
</html>

●結果

10000回やっても、5が1回も出てません。
OKですね。

ちなみに、
除外したい数字が複数ある場合は、
配列でも渡せるように関数を修正しました。

$except_num = [2, 3, 5];        // 除外したい数字の配列

...

function mt_rand_except( int $min, int $max, $except ) : int {

    if (gettype($except) == 'array'){

        do {
            $num = mt_rand($min, $max);
        } while (in_array($num, $except));

    } else {

        do {
            $num = mt_rand($min, $max);
        } while ($num == $except);

    }

    return $num;
}

●結果

はい。
ちゃんと2、3、5が除外されて返されています。

カテゴリーphp

コメントを残す

メールアドレスが公開されることはありません。