核心答案:日常「随机数」几乎都是伪随机——用确定性算法从种子算出貌似无规律的序列。种子相同,序列完全相同。这对游戏、模拟足够;但密码、密钥必须用基于物理噪声的真随机或加密级随机数生成器(CSPRNG)。
伪随机与真随机
| 类型 | 来源 | 可复现 | 典型用途 |
|---|---|---|---|
| 伪随机(PRNG) | 数学算法(如梅森旋转) | 是(同种子同序列) | 游戏、模拟、抽样 |
| 加密随机(CSPRNG) | 系统熵池 + 加密算法 | 否 | 密码、Token、密钥 |
| 真随机(TRNG) | 物理噪声(热噪声、量子) | 否 | 彩票摇奖、军事密钥 |
JS 的 Math.random() 是伪随机且非加密安全;安全场景用 crypto.getRandomValues()。
随机数怎么生成
线性同余法(经典教学模型):Xₙ₊₁ = (aXₙ + c) mod m
- 选好 a、c、m 可让周期达到 m
- 实例:a=1103515245、c=12345、m=2³¹(glibc 经典参数)
- 种子 X₀ 决定整条序列——「时间戳做种子」是常见做法
梅森旋转算法:周期 2¹⁹⁹³⁷−1,Python/JS 引擎的主流默认,统计性质优异。
常见应用场景
- 抽奖/抽签:均匀分布整数,1-N 每数概率 1/N
- 游戏:暴击判定、掉落率(如 20% 暴击 = 随机数 < 0.2 触发)
- 模拟(蒙特卡洛):大量随机采样估算 π、积分、风险
- 洗牌:Fisher-Yates 算法 O(n) 且无偏
- 验证码/临时密码:必须 CSPRNG
随机范围与公平性
- [min, max] 整数公式:Math.floor(Math.random() × (max−min+1)) + min
- 1-100:floor(random × 100) + 1
- 常见偏差:用 random() % n 取模,当 n 不整除范围长度时小数字概率略高(模偏差),正式场景用拒绝采样
实例:班级 45 人抽 1 人答问,random 生成 1-45 每人生概率 2.22%;连抽 3 人不重复需记录已抽编号排除。
常见误区
- 「连续 5 次正面,下次反面概率大」:赌徒谬误。独立事件概率不变,硬币无记忆
- Math.random() 生成密码:可被预测(种子可推断),必须用 crypto.getRandomValues()
- 「随机就是没有规律」:真随机也允许出现 11111——均匀随机长串中必然出现局部「规律」片段
- 手动乱按键盘当随机源:人类「随机」行为高度可预测(偏爱中间区域、回避重复)