現在の位置: ホーム> 最新記事一覧> MT_GETRANDMAX()とMT_RAND()を一緒に使用する場合、どのような一般的な問題が発生しますか?避ける方法

MT_GETRANDMAX()とMT_RAND()を一緒に使用する場合、どのような一般的な問題が発生しますか?避ける方法

gitbox 2025-06-12

在php中mt_rand()个常用的伪随机数生成函数它使的是它使用的是mersenne twister

1。MT_GETRANDMAX ()返回值的误解

mt_getrandmax()的作用是返回mt_rand()所能生成的最大随机整数所能生成的最大随机整数2147483647

例如:

 <span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-title function_ invoke__">mt_getrandmax</span></span><span>(); </span><span><span class="hljs-comment">// &#36755;&#20986;&#65306;2147483647</span></span><span>
</span></span>

问题出现点:如果你基于该返回值来进行归一化处理(如生成 0到1

2。

mt_rand()支持两个参数:最小值和最大值。如果你将最大值设置为大于mt_getrandmax()的值、会怎样?

 <span><span><span class="hljs-variable">$min</span></span><span> = </span><span><span class="hljs-number">0</span></span><span>;
</span><span><span class="hljs-variable">$max</span></span><span> = </span><span><span class="hljs-title function_ invoke__">mt_getrandmax</span></span><span>() + </span><span><span class="hljs-number">1</span></span><span>;
</span><span><span class="hljs-variable">$rand</span></span><span> = </span><span><span class="hljs-title function_ invoke__">mt_rand</span></span><span>(</span><span><span class="hljs-variable">$min</span></span><span>, </span><span><span class="hljs-variable">$max</span></span><span>); </span><span><span class="hljs-comment">// &#21487;&#33021;&#20135;&#29983;&#35686;&#21578;&#25110;&#19981;&#20934;&#30830;&#30340;&#32467;&#26524;</span></span><span>
</span></span>

问题出现点:虽然php

3。

很多人认为mt_rand()可以生成真正“均匀”的随机数0到100之间的随机浮点数:

 <span><span><span class="hljs-variable">$randFloat</span></span><span> = </span><span><span class="hljs-title function_ invoke__">mt_rand</span></span><span>() / </span><span><span class="hljs-title function_ invoke__">mt_getrandmax</span></span><span>();
</span><span><span class="hljs-variable">$result</span></span><span> = </span><span><span class="hljs-title function_ invoke__">floor</span></span><span>(</span><span><span class="hljs-variable">$randFloat</span></span><span> * </span><span><span class="hljs-number">101</span></span><span>); </span><span><span class="hljs-comment">// &#24076;&#26395;&#26159; 0-100 &#30340;&#25972;&#25968;</span></span><span>
</span></span>

问题出现点:由于浮点运算和整数舍入的问题、这种方法可能会导致边界值(如 0 或100))

更稳妥的写法:

 <span><span><span class="hljs-variable">$result</span></span><span> = </span><span><span class="hljs-title function_ invoke__">mt_rand</span></span><span>(</span><span><span class="hljs-number">0</span></span><span>, </span><span><span class="hljs-number">100</span></span><span>); </span><span><span class="hljs-comment">// &#30452;&#25509;&#20351;&#29992;&#25972;&#25968;&#21306;&#38388;</span></span><span>
</span></span>

或者如果你真的需要一个浮点数:

 <span><span><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span> </span><span><span class="hljs-title">mt_rand_float</span></span><span>(</span><span><span class="hljs-params"><span class="hljs-variable">$min</span></span></span><span> = </span><span><span class="hljs-number">0</span></span><span>, </span><span><span class="hljs-variable">$max</span></span><span> = </span><span><span class="hljs-number">1</span></span><span>) {
    </span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-variable">$min</span></span><span> + (</span><span><span class="hljs-title function_ invoke__">mt_rand</span></span><span>() / </span><span><span class="hljs-title function_ invoke__">mt_getrandmax</span></span><span>()) * (</span><span><span class="hljs-variable">$max</span></span><span> - </span><span><span class="hljs-variable">$min</span></span><span>);
}
</span></span>

4。

在需要使用随机数生成一个特定概率分布(例如权重选择、正态分布等)时错误地使用mt_getrandmax()可能会使结果偏离预期。例如、某些开发者会用以下方式实现带权重的随机选择:

 <span><span><span class="hljs-variable">$rand</span></span><span> = </span><span><span class="hljs-title function_ invoke__">mt_rand</span></span><span>(</span><span><span class="hljs-number">1</span></span><span>, </span><span><span class="hljs-title function_ invoke__">mt_getrandmax</span></span><span>());
</span></span>

然后将这个值映射到各权重区间中。问题是、特别是当总权重数量远小于mt_getrandmax()时。

更安全的做法是:

在已知最大权重总和的前提下、直接使用:

 <span><span><span class="hljs-variable">$rand</span></span><span> = </span><span><span class="hljs-title function_ invoke__">mt_rand</span></span><span>(</span><span><span class="hljs-number">1</span></span><span>, </span><span><span class="hljs-variable">$totalWeight</span></span><span>);
</span></span>

这样可以确保精度和分布合理性。

5。

虽然mt_rand()的随机性足够日常使用但在高频调用(如循环中快速生成多个随机数 但在高频调用(如循环中快速生成多个随机数)、可能会遇到重复值。

例如:

 <span><span><span class="hljs-keyword">for</span></span><span> (</span><span><span class="hljs-variable">$i</span></span><span> = </span><span><span class="hljs-number">0</span></span><span>; </span><span><span class="hljs-variable">$i</span></span><span> &lt; </span><span><span class="hljs-number">1000000</span></span><span>; </span><span><span class="hljs-variable">$i</span></span><span>++) {
    </span><span><span class="hljs-variable">$r</span></span><span> = </span><span><span class="hljs-title function_ invoke__">mt_rand</span></span><span>();
    </span><span><span class="hljs-comment">// &#32479;&#35745;&#37325;&#22797;&#29575;</span></span><span>
}
</span></span>

问题出现点: Mersenne Twister

解决方案:

为每个线程或请求设置不同的种子:

 <span><span><span class="hljs-title function_ invoke__">mt_srand</span></span><span>(</span><span><span class="hljs-title function_ invoke__">crc32</span></span><span>(</span><span><span class="hljs-title function_ invoke__">uniqid</span></span><span>(</span><span><span class="hljs-string">''</span></span><span>, </span><span><span class="hljs-literal">true</span></span><span>)));
</span></span>

当然、PHP 7.1起已不推荐手动调用MT_SRAND()、PHP

总结

mt_rand()mt_getrandmax()是php提供的强大但需要谨慎使用的函数。常见的误区包括错误理解mt_getrandmax()

要避免这些问题、应注意:

  • 不要假设MT_GETRANDMAX()会随系统变化;

  • 不应将mt_rand()的最大值设为超过mt_getrandmax()

  • 用整数直接控制范围更安全;

  • 高并发或多线程中考虑手动设定种子;

  • 对于安全性要求高的场景对于安全性要求高的场景and random_int()random_bytes()代替。

掌握这些细节可以让你在使用可以让你在使用mt_rand()系列函数时更加得心应手、避免潜在バグ。更多实例可参考:
https://gitbox.net/php/mt_rand_examples