mt_rand([int $min, int $max])で $min > $max のときの挙動
まぁ、$min < $max でないときの挙動を気にする必要はないのだけれど、mt_rand(0, -100)
と入れた場合も、エラーはでずに、-25 とか -86 とか返って来てうまく動いているようにみえる。けど、乱数のレンジが微妙。
サンプルコードを書いてみる。
<?php list(, $min, $max) = $argv; foreach (range($min, $max) as $i) { $x[$i] = 0; } for ($i = 0; $i < 10000; ++$i) { $x[mt_rand($min, $max)]++; } print_r($x); ?>
list()とかrange()とかべんりですね。
で、指定のmin、maxから10,000回コールの分布をみてみる。
正常! ($min < $max)
ちゃんと0から10まで均等に分布してます
$ php rand.php 0 10 Array ( [0] => 949 [1] => 912 [2] => 898 [3] => 910 [4] => 870 [5] => 940 [6] => 914 [7] => 930 [8] => 899 [9] => 921 [10] => 857 ) $ php rand.php -5 5 Array ( [-5] => 875 [-4] => 889 [-3] => 889 [-2] => 904 [-1] => 905 [0] => 904 [1] => 900 [2] => 903 [3] => 957 [4] => 927 [5] => 947 )
異常
$ php rand.php 0 -10 Array ( [0] => 1120 [-1] => 1121 [-2] => 1108 [-3] => 1070 [-4] => 1117 [-5] => 1122 [-6] => 1089 [-7] => 1121 [-8] => 1132 [-9] => 0 [-10] => 0 ) $ php rand.php 5 -5 Array ( [5] => 1065 [4] => 1161 [3] => 1114 [2] => 1100 [1] => 1077 [0] => 1125 [-1] => 1090 [-2] => 1089 [-3] => 1179 [-4] => 0 [-5] => 0 )
$max側の2つが表れてないことがわかります。
$ php rand.php 10 8 Array ( [10] => 10000 [9] => 0 [8] => 0 )
で、$i == mt_rand($i, $i - 2)
になりそう。
ソース
ソースコードでは、一旦、 (long) (php_mt_rand(TSRMLS_C) >> 1); で、0 〜 PHP_MT_RAND_MAX の乱数を生成して、範囲が指定されている場合に、
#define RAND_RANGE(__n, __min, __max, __tmax) \ (__n) = (__min) + (long) ((double) ( (double) (__max) - (__min) + 1.0) * ((__n) / ((__tmax) + 1.0)))
のマクロで範囲に変換してるのですが、算数力が低下していて読み解くのめんどくさくなって挫折。
追記
mt_rand([int $min, int $max])で $min > $max のときの挙動 (理由解説編) - おぎろぐはてなで、このマクロの動きと、それによって起こる上のような問題について解説してます。