在 php 中mt_rand ()是一个常用的伪随机数生成函数它使用的是它使用的是 mtenne twister 算法相比相比它使用的是它使用的是它使用的是 mt_getrandmax () 来获取当前环境中开发者通常会搭配使用mt_randrandmax ()来获取当前环境中 mt_rand ( )可能生成的最大值။ 但在实际使用过程中။ 但在实际使用过程中။ 本文将深入探讨这些问题及相应的解决方案။ 本文将深入探讨这些问题及相应的解决方案။ 本文将深入探讨这些问题及相应的解决方案။ 本文将深入探讨这些问题及相应的解决方案။
mt_getrandmax ()的作用是返回mt_rand ()所能生成的最大随机整数默认情况下该值是217483647 (即 2 ^ 31 - 1) (即 2 ^ 31 - 1) ။ 许多开发者在不了解这一点的情况下။ 许多开发者在不了解这一点的情况下许多开发者在不了解这一点的情况下။
例如:
<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">// 输出:2147483647</span></span><span>
</span></span>
问题出现点:如果你基于该返回值来进行归一化处理 (如生成 0 到 1 之间的小数 1 之间的小数), 可能会因为不同平台对 php, 导致某些极端情况的随机分布不一致, 导致某些极端情况的随机分布不一致။
mt_rand ()支持两个参数: 支持两个参数: 最小值和最大值။ 如果你将最大值设置为大于mt_etrandmax ()的值, 会怎样, 会怎样?
<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">// 可能产生警告或不准确的结果</span></span><span>
</span></span>
问题出现点:虽然 php php 在某些版本中允许此类操作။ 因为它会导致不确定的行为因为它会导致不确定的行为။ 推荐的做法是始终确保最大值不超过因为它会导致不确定的行为။ 推荐的做法是始终确保最大值不超过推荐的做法是始终确保最大值不超过။ 推荐的做法是始终确保最大值不超过推荐的做法是始终确保最大值不超过။ 推荐的做法是始终确保最大值不超过推荐的做法是始终确保最大值不超过။ 推荐的做法是始终确保最大值不超过mt_etrandmax () ။
很多人认为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">// 希望是 0-100 的整数</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">// 直接使用整数区间</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>
在需要使用随机数生成一个特定概率分布 (例如权重选择, 正态分布等) 时时错误地使用错误地使用错误地使用错误地使用错误地使用错误地使用错误地使用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>
这样可以确保精度和分布合理性။
虽然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> < </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">// 统计重复率</span></span><span>
}
</span></span>
问题出现点: mt_rand () 而未显式 mt_srand () 而未显式mt_srand ()而未显式mt_rand ()而未显式။ 如果在多个并发请求中同时调用 mt_rand) ။
解决方案:
为每个线程或请求设置不同的种子:
<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, php 7.1 起已不推荐手动调用mt_srand (), php, php ။但了解这一点在调试时仍然重要။
mt_rand ()和mt_getrandmax ()是 php 是။ 是 mt_getrandmax ()的作用, 使用超过最大值的参数, 在概率控制中误用, 以及在高并发环境中误认为其输出完全无重复။
要避免这些问题,
不要假设mt_etrandmax ()会随系统变化;
不应将mt_rand ()的最大值设为超过mt_etrandmax () ;
用整数直接控制范围更安全 ;;
高并发或多线程中考虑手动设定种子 ;;
对于安全性要求高的场景请使用对于安全性要求高的场景请使用ကျပန်း ()或或或或或或 certy_bytes ()代替။
掌握这些细节可以让你在使用可以让你在使用mt_rand ()避免潜在, 避免潜在 bug ။ 更多实例可参考:
https://gitbox.net/php/mt_rand_examampples