随机数生成

指定范围、个数、去重与小数,基于 crypto 加密级随机源生成。

—

随机数生成:为什么随机源和偏差都重要

两个容易忽略的技术要求

"随机"在程序里不是一件事,而是两件事:随机源的质量和分布是否均匀。两个都做对,结果才真正等概率。

随机源:Math.random 不够用

JavaScript 里的 Math.random() 是伪随机数生成器。它的输出由一个内部状态经过确定性运算得到,只要状态被推出,后续序列就能被预测。对于游戏、抽样、测试数据这类场景够用;但一旦涉及抽奖结果、无法被他人预测的选择、密钥或 token 生成,就不能用。

本工具使用 crypto.getRandomValues(),即浏览器的密码学安全随机源,由操作系统的熵池提供,不依赖可推导的内部状态。

分布:取模偏差

即使随机源是安全的,把它映射到指定区间的方式也可能引入偏差。以"取随机 uint32 值然后对范围取模"为例:如果范围大小不能整除 232,那么区间前一部分数字会分到略多的随机值,出现概率偏高。

举例:想生成 1 到 3(范围大小 3),而随机源均匀产生 0 到 4294967295。取模 3 之后,0、1、2 各类的取值个数相差 1 个——这个差异在 43 亿的分母下小到几乎测不出,但如果范围更大、或者随机源位数更少(比如只用 8 位生成 1-3),偏差就会明显到能被统计出来。

本工具使用拒绝采样:当随机值落在"会引入偏差"的尾部区间时直接丢弃并重新取,直到取值落在可均匀分配的范围内。代价是极少数情况下多取几次,换来的是严格等概率。

怎么验证?生成大量结果做分布统计,每个值的出现次数应该接近均匀。幅度大的偏差用几千次抽样就能看出来,极小的偏差需要更多样本——但推导方式是否正确是可以从实现上确认的,不必只靠抽样检验。

去重(不放回抽样)

勾选去重后,同一个数字不会重复出现,这在统计学上叫不放回抽样。实际用途就是抽奖、随机排序、从名单里选几个人。

去掉重复本质上需要一个"生成不重复序列"的算法,常见做法是先构造完整候选集再洗牌(Fisher–Yates),或者反复生成直到得到新值(当"要选的数量接近候选总数"时,后者会越采越慢)。本工具的做法属于后者,并专门检查了一个边界情况:如果要求的个数大于区间内的整数数量(比如在 1-10 里要不重复的 20 个整数),数学上不可能,工具会直接提示"个数超过范围大小",而不是陷入无限循环。

这个检查很重要:没有它,程序会挂死。自己写抽奖逻辑时也容易漏掉这一步。

可复现性

密码学安全随机源无法设定种子——这是它的设计目标。所以本工具的结果不可复现:关掉页面重开,同样的输入不会得到同样的输出。

需要可复现的随机(做实验、生成可重复的测试数据、需要复核的抽样)时,要用可设定种子的伪随机生成器(如各语言的 mt19937 / xorshift 实现),把种子记录下来。这两种需求是冲突的:要么不可预测,要么可复现,不能同时满足。

适用与不适用

场景是否合适说明
抽奖、随机选人、随机排序合适勾选去重即可
生成测试数据、抽样检查合适需要可复现时改用带种子的方案
随机颜色、随机坐标、模拟合适小数模式有用
生成密码建议用专门的密码工具密码需要从字符集里采样并做强度评估,本工具的区间模型不适合
生成密钥、token、会话 ID不合适应该用平台提供的密钥生成 API(crypto.randomUUID、secrets 模块等),它们保证了长度与编码的正确性
抽奖结果的公平性审计不合适前端生成的结果无法被第三方验证,需要可审计的服务端方案

最后一行值得强调:在前端"随机"决定抽奖结果,无论随机源多好,都无法阻止用户重跑或直接修改结果。抽奖必须在服务端做,并保留可核验的记录。

工具怎么用

填最小值、最大值、个数(1 到 1000),可选去重与小数(保留 2 位)。点生成后每行一个结果,可一键复制。区间是闭区间,最大值本身也在候选范围内。

生成在浏览器本地完成,不需要网络请求。

常见问题

随机质量如何保证?

使用 crypto.getRandomValues 加密级随机源,并采用拒绝采样保证区间内每个整数等概率,避免取模偏差。

去重时个数超过范围会怎样?

整数去重时若个数大于范围内整数数量,工具会提示“个数超过范围大小”,避免死循环。