随机数生成器

可选择整数或小数、是否允许重复,以及随机数的来源,结果会同时显示总和与平均值。

这个生成器如何产生随机数

默认使用浏览器的 crypto.getRandomValues(Web Crypto接口,背后是操作系统的密码学随机数生成器)取随机数。整数范围内,只取范围所需的比特数,超出范围的值就丢弃重抽,这叫拒绝采样,可以保证每个数的概率完全相同。 “不重复抽取”使用费舍尔-耶茨(Fisher-Yates)洗牌的部分洗牌。取消勾选“密码学随机数”后,会改用JavaScript自带的 Math.random()。 两种方式都保留,是因为抽奖和游戏里你感觉不到区别,但应该知道在什么场合区别才有意义。 密码、令牌这类需要安全性的值,请不要用屏幕上显示的数字,而是用密码生成器或UUID生成器这样的专用工具。

伪随机数与密码学随机数

计算机里的“随机数”大多是伪随机数:由一个很小的内部状态按公式不断算出下一个值,看上去随机,但只要知道状态就能预测之后的全部结果。Math.random() 追求的是速度和统计质量,并不保证不可预测;算法由各引擎自行决定,Chrome和Edge使用的V8曾采用128位状态的xorshift128+。 而 crypto.getRandomValues 按规范要使用操作系统的密码学安全随机数生成器,即使知道此前的输出也无法推算后面的值。

Math.random()crypto.getRandomValues
性质伪随机数(重统计与速度)密码学安全的随机数
可预测性有足够输出时可推断内部状态以不可预测为设计目标
指定种子、复现不可以(由浏览器设定)不可以
适合用途游戏、模拟、日常抽签令牌、密钥、密码、对公平性要求高的抽奖

本页两种方式都无法指定种子,所以不能重现同一个结果。需要可复现的随机数(实验复现、测试数据)时,请在自己的代码里使用支持种子的伪随机库。 反过来,抽奖恰恰需要这种“无法提前算出、也无法重来”的特性。

取模偏差:为什么“随机数 % 范围”不公平

一种常见的错误做法,是把32位随机数(0到4,294,967,295,共232种)对范围大小N取余。只要232不是N的倍数,余数r个结果就会各多对应一个原始值,较小的数会略微更常出现。 以骰子(N=6)为例,232 = 6 × 715,827,882 + 4,所以1到4出现的机会是5和6的715,827,883/715,827,882倍,也就是多出约十亿分之1.4。实际可以忽略,但范围一大差距就迅速扩大。

范围大小N232 mod N (r)概率偏高的结果占比它们多出的概率53位小数法的误差上限(N/253)
6466.67%+1.4e-7%6.7e-16
453168.89%+1.0e-6%5.0e-15
1009696.00%+2.3e-6%1.1e-14
1,00029629.60%+2.3e-5%1.1e-13
1,000,000967,29696.73%+0.023288%1.1e-10
1,000,000,000294,967,29629.50%+25.00%1.1e-7

范围达到十亿时,约29.50%的结果比其他结果多出25.00%的概率,这是肉眼可见的偏差。本工具避免了这个问题:例如N=100时,取7个比特(0到127),遇到100及以上就丢弃重抽。丢弃概率始终低于50%,平均不到两次就能得到结果,所有值的概率完全相等。Math.random() 模式是 Math.floor(Math.random() * N),由于其产生的是53位小数,偏差上限约为N/253(表中最后一列),在范围不超过232时可以忽略;范围更大时,工具不会使用Math.random,而是自动切换到密码学随机数。

整数与小数范围的注意点

整数模式的最小值和最大值都包含在内。1到6时范围大小是6,每个数的概率是1/6。范围大小按(最大值 − 最小值 + 1)计算,−10到10这样的负数范围也一样。 常见的错误是写成 Math.floor(Math.random() * (max - min)) + min,这样永远出不了max。

小数模式是把[0,1)内的均匀随机数乘以(最大值 − 最小值),加上最小值,再按指定位数四舍五入。由于四舍五入,结果可能等于最大值,位数越少越容易出现重复值。 比如在0到1之间取1位小数,候选值有0.0到1.0共11个,但两端各只占半个舍入区间,出现概率只有其他值的一半。如果需要每个候选值概率相同,请抽0到10的整数再除以10。小数模式下“不重复”不适用。

允许重复与不重复的区别

允许重复(有放回抽样)时,每次抽取的条件都相同,所以同一个数出现两次是正常的。抽取的个数越多,出现重复反而越是意料之中的事。

范围大小N抽取个数k至少有一对重复的概率
45629.4%
1001037.2%
3652350.7%
1,0005071.2%
1,000,0001,00039.3%

在1到100中允许重复地抽10个数,至少有一对相同的概率是37.2%。著名的“生日问题”是同样的计算:365天里23个人,有人同一天生日的概率为50.7%。 所以“出现重复就说明随机数有问题”这个判断几乎总是错的。中奖号码、座位号这类不能重复的场合,请勾选“不重复抽取”。

不重复抽取(无放回)是先把范围内所有值排成一列,依次让第i个位置与“第i到最后”中均匀随机选出的位置交换,重复k次后取前k个。这样所有有序的k个不同值的组合概率都相同。 范围超过一百万时不建立列表,而是记住已抽到的值,遇到重复就重抽;本工具一次最多抽1,000个,所以不影响均匀性。

检验过的算例

算例1:1到45中不重复抽6个。不计顺序的组合数是C(45,6) = 8,145,060,每一组的概率都是1/8,145,060;计顺序则乘以6! = 720,共5,864,443,200种。 “1,2,3,4,5,6”出现的概率与“7,13,21,30,38,44”完全一样,看起来整齐的组合并不会更少出现。专门选号可以看彩票号码生成器。

算例2:1到45中允许重复抽6个。有序结果共456 = 8,303,765,625种,再次抽到某个特定序列的概率为1.20e-10。六个数里至少有一对相同的概率是29.38%(重复概率表第一行)。

算例3:10到19中不重复抽3个。范围大小是19 − 10 + 1 = 10,有序结果共10 × 9 × 8 = 720种。三个数必定互不相同,总和在最小10+11+12 = 33与最大17+18+19 = 54之间。如果显示的总和超出这个范围,就说明有问题。

常见错误与误解

不适合使用本工具的场合

具有法律效力的奖品抽取需要见证人、记录或第三方来证明公平,本页无法提供这些;也不能用于赌博。请不要把屏幕上显示的数字当作密码、一次性验证码或加密密钥。 数字在浏览器内存中生成,本页不会发送或保存;由于没有种子,之后也无法重现同一结果,需要留存时请自行复制结果。

如何使用结果

抽奖时,把参与者编号的最小值、最大值填入范围,勾选“不重复抽取”,按中奖人数抽取即可。要把人分组可用随机分组工具,要逐个分配结果可以玩梯子游戏,骰子、硬币这类小范围的反复试验用抛硬币 & 掷骰子更方便。 做模拟时可以加大个数,看总和与平均值是否趋近期望值:1到100均匀整数的期望平均值是50.5,样本越大越接近。

常见问题

什么时候使用“不重复抽取”?

中奖号码、座位号、彩票选号这类同一个数不能出现两次的场合。如果要求的个数超过范围大小(例如在1到10里抽11个),这是不可能的,工具会提示错误。

这些数字是真正的随机吗?

计算机产生的随机数,严格说是基于算法和操作系统收集的熵。默认的密码学方式很难被预测,用于抽奖、游戏和学习完全足够。取消勾选后使用的Math.random在统计上没有问题,但不保证抗预测,不适合安全用途。

同样的设置连续点击却出了相同的数,是错误吗?

不是。范围越小越容易偶然相同,在1到6的范围里连续两次相同的概率是1/6(约16.7%)。

可以指定种子来得到相同结果吗?

不可以。两种随机数都由浏览器内部管理,无法指定种子。需要可复现的测试或实验,请使用支持种子的伪随机库。

小数模式会抽到最大值吗?

会。内部的值小于最大值,但按指定位数四舍五入后,显示值可能恰好等于最大值。需要严格区分包含与不包含时,请使用整数模式。

一次最多能抽多少个?

每次最多1,000个,范围不能超出可被整数精确表示的大小(253以内)。

相关工具