Laravel 里的真随机:一个取模偏差让 22 张牌多出 33% 的出场率
来源:dev.to — 2026-09-01
📋 概述
作者用一句看似无害的 PHP 代码揭示了取模偏差的致命之处:ord(random_bytes(1)) % 78 虽然永远返回 0 到 77 的合法值、任何常规测试都通过,但 256 不是 78 的倍数,多出的 22 个字节会回绕,导致 22 张牌比另外 56 张多出现 33%——在生产环境里静默运行。解法是拒绝采样:丢弃落在不均匀尾部的字节重新抽取。洗牌算法同样藏有 nⁿ/n! 版本的同类偏差。作者还分享了自己把随机数来源做成可配置链(ANU 量子、random.org、系统 CSPRNG)的 lararand 包,因为"我们调用了 random_int"这句话不足以卖给客户。
🔑 核心要点
- ord(random_bytes(1)) % 78 存在取模偏差:22 张牌每 256 字节出现 4 次,比另 56 张多 33%
- 常规测试只检查值的形状(范围、非空),永远测不出分布偏差
- 修复用拒绝采样:limit=intdiv(256,78)*78,丢弃落在尾部的字节重新抽取
- 洗牌算法的 nⁿ/n! 路径数分布不均是同一类偏差的另一种伪装
- lararand 把随机源做成可配置链(ANU 量子噪声、random.org、系统 CSPRNG),首个可用的提供字节
💡 金句
'我们的彩票运行在澳大利亚国立大学测得的量子真空噪声上'是能对客户说的话;'我们调用了 random_int'不是——尽管它在技术上更正确。
👍 0
👎 0
← 返回 dev.to 首页