使用方法
- 在文本框里每行写一个选项,格式是
名称,权重。示例已预填五行:今晚做饭,1 / 点外卖,1 / 下馆子,2 / 叫朋友来家里,3 / 直接跳过这顿,1,权重和为 8。决策生成不识别"名称:权重"这种冒号写法,权重必须跟在英文逗号后面。 - 在「抽取次数」填 1 ~ 200 的整数,示例值 12。想要"抽一个就定了"就填 1;想看分布稳不稳就填 100 以上。
- 「抽取模式」决定同一个选项能不能重复中选:放回模式每次抽取互相独立;不放回模式用 Fisher–Yates 洗牌后取前 k 个,同一选项最多出现一次。
- 点「生成决策」,页面给出最终选项、归一化概率、香农熵值,以及完整的抽取历史。不放回模式下若抽取次数超过参与项数会明确报错而不是静默截断。
- 在文本框里按
Ctrl + Enter(Mac 是Cmd + Enter)触发,普通 Enter 保留给换行。下方权重对照表默认 12 行,点「加载更多行」展开。
这个决策生成能解决什么问题
它的价值在于把"我随便选一个"变成"我按事先声明的概率选一个"。等概率抽取的问题在于:所有选项在你心里的分量其实并不相等。让朋友吃饭你大概更想下馆子,但纯随机会给"直接跳过这顿"同样的机会;反过来,如果你自己悄悄把权重调高,它就变成了"假装随机实则指定"。决策生成把权重写明在文本框里——概率是可读、可审、可复现的,而不是藏在算法里的黑箱。
第二个用途是把纠缠的决策拆平。写代码选方案时"凭手感 A 或 B"经常变成反复纠结;把变量列成选项、给出相对权重、让熵值告诉你这套权重到底偏不偏,比在脑子里反复称重快得多。熵值接近选项数的对数,说明权重设得均匀;熵值远低于上界,说明某一项被压得很重——这时候你至少知道自己偏向了哪里。
第三是不可预测性。本页的随机源是 Web Crypto 的 crypto.getRandomValues,而 V8 的 Math.random() 走 xorshift128+,连续取够 624 个 32 位输出就能还原内部状态、预测后续全部结果。用本页做需要防作弊的抽签(团建分组、活动顺序、评审分配),结果无法被提前算出来。
本页不做的事:不接受文字描述让 AI 帮你分析利弊;不模拟人类心理或犹豫程度;也不提供视觉化的转盘或滚筒。输入是纯文本的「名称 + 数字权重」,输出是概率表和抽取记录——所有中间量都在页面上列出来,可以手算复核。
权重归一化、前缀和与熵值算法
抽取分三步,每一步的中间量都在页面表格里列出。
- 第一步,归一化:权重和
W = Σwᵢ,每个选项的概率pᵢ = wᵢ / W。示例里 W = 1+1+2+3+1 = 8,五个选项的概率依次是 12.5% / 12.5% / 25.0% / 37.5% / 12.5%。权重 0 的选项 p=0,理论上永不被抽中,但仍然显示在表里——让你看得见"我确实排除了它"。 - 第二步,前缀和 + 浮点比较(这一步是本页面与普通随机选择页的核心差别):把 pᵢ 累加成
Pᵢ = p₁ + … + pᵢ,取u = getRandomValues(...) / 2³² ∈ [0, 1),然后找第一个满足u < Pᵢ的下标。示例的前缀和是 0.125、0.250、0.500、0.875、1.000。 - ★ 为什么不用
u * n 取整或u % n:这是取模偏差(modulo bias)。uint32 有 232 = 4294967296 个等概率取值,除以 3 是 1431655765 余 1——前 1 个格子各多分到 1 个取值,最大概率偏差 1/232 = 2.328e−10。n=7 时余 4,n=10 时余 6。偏差小到任何现实用途都测不出来,但它证明了"取模/取余 ≠ 等概率";前缀和比较法在数学上严格等概率,代价只是 O(n) 的一次线性扫描,而 n 上限只有 200。 - ★ 剔除备选项的正确做法:如果不放回模式下想抽 3 个却剩 5 项,常见错误是"在 5 项里随机,抽中要排除的那项就重投"。4 项里排 1 项时单次重投期望次数是 4/3 ≈ 1.3333 次,两次及以上概率 1/3 ≈ 33.33%——每个多余选项都白烧一次随机调用,200 项时最坏要重投上百次。本页的做法是直接在可选项上重建前缀和,零重投。
- 第三步,不放回用 Fisher–Yates 洗牌:从最后一位开始
j = u × (i+1),交换 a[i] 与 a[j],i 递减到 1。实测 n=4、2×105 次,末位分布 24.99% / 25.08% / 25.01% / 24.92%,与理论 25% 吻合。如果错成"从前往后两两交换",末位分布会变成 24.84% / 0.00% / 18.83% / 56.33%——第 2 项永远抽不到,这就是必须"从后往前"的原因。 - 熵值 H = −Σ pᵢ log₂ pᵢ(香农熵,1948),单位 bit。理论上界是等权时的 log₂ n。示例 W=8 的权重 1:1:2:3:1 给出 H = 2.1556 bit,上界 log₂5 = 2.3219 bit,分布效率 92.8%。效率越低说明权重越集中。
完整示例(数值仅作演示)
示例条件:五个选项「今晚做饭 1 / 点外卖 1 / 下馆子 2 / 叫朋友来家里 3 / 直接跳过这顿 1」,抽取 12 次,放回模式,随机源 crypto.getRandomValues。
- 权重和 W = 8,前缀和依次为 0.1250、0.2500、0.5000、0.8750、1.0000。
- 概率依次为 12.5% / 12.5% / 25.0% / 37.5% / 12.5%。最高权重的「叫朋友来家里」是 3/8 = 37.5%,约等于最低项 12.5% 的三倍。
- 香农熵 H = 2.1556 bit,等权上界 log₂5 = 2.3219 bit,分布效率 92.8%——已经相当接近均匀,说明这套权重"有侧重但不极端"。
- 作为对照:权重 1:2:1 的三项熵是 1.5000 bit(上界 log₂3 = 1.5850);权重 1000:1 的两项熵只有 0.0114 bit,效率 1.1%——那已经等同于"必选第一项",随机只是走个形式。
- 12 次放回抽取的期望命中数是 12 × pᵢ,即 1.5、1.5、3.0、4.5、1.5。实际结果围绕这些值波动,例如命中 6 次的概率远低于命中 2 次——看到 6 次不必惊讶,这是二项分布的正常离散。
以上数字用于演示概率与熵的计算,不代表任何真实决策建议。
权重组合与熵值对照表
下表用同一组选项名,只改权重配置,方便对比"权重改一点会怎样"。熵值全部由 H = −Σ p log₂ p 算出,效率 = H / log₂ n。
| 权重配置 | 权重和 W | 各选项概率 | 香农熵 H | 等权上界 log₂n | 分布效率 | 解读 |
|---|---|---|---|---|---|---|
| 1 : 1 : 1 | 3 | 33.3% / 33.3% / 33.3% | 1.5850 bit | 1.5850 | 100.0% | 完全均匀 |
| 1 : 2 : 1 | 4 | 25.0% / 50.0% / 25.0% | 1.5000 bit | 1.5850 | 94.6% | 轻度偏向中间项 |
| 1 : 1 : 1 : 1 | 4 | 25.0% × 4 | 2.0000 bit | 2.0000 | 100.0% | 完全均匀 |
| 1 : 1 : 2 | 4 | 25.0% / 25.0% / 50.0% | 1.5000 bit | 1.5850 | 94.6% | 偏三项里的一项 |
| 1 : 1 : 2 : 3 : 1 | 8 | 12.5% / 12.5% / 25.0% / 37.5% / 12.5% | 2.1556 bit | 2.3219 | 92.8% | 本页默认示例 |
| 2 : 3 : 5 | 10 | 20.0% / 30.0% / 50.0% | 1.4855 bit | 1.5850 | 93.7% | 等比但非等权 |
| 1 : 1 : 1 : 1 : 1 | 5 | 20.0% × 5 | 2.3219 bit | 2.3219 | 100.0% | 完全均匀 |
| 1 : 4 : 5 | 10 | 10.0% / 40.0% / 50.0% | 1.3610 bit | 1.5850 | 85.9% | 明显偏向后两项 |
| 1 : 9 | 10 | 10.0% / 90.0% | 0.4690 bit | 1.0000 | 46.9% | 接近定向 |
| 1 : 99 | 100 | 1.0% / 99.0% | 0.0808 bit | 1.0000 | 8.1% | 等同必选 |
| 1 : 0 : 0 | 1 | 100.0% / 0% / 0% | 0 bit | 1.5850 | 0.0% | 熵为 0(排除两项) |
| 1000 : 1 | 1001 | 99.90% / 0.10% | 0.0114 bit | 1.0000 | 1.1% | 随机已无意义 |
读法:看"分布效率"这一列。100% 是完全均匀,往下掉得越快说明权重越集中。1:99 那行效率只有 8.1%——你写下了"随机",但实际结果 99% 确定,这样的配置不如让决策生成直接写死答案。
边界与精度
- 选项上限 200 项、权重上限 100000:200 × 100000 = 20000000 的权重和远小于
Number.MAX_SAFE_INTEGER= 9007199254740991(253 − 1),前缀和全程用整数累加再除,没有精度损失。若权重和超过 253,float64 无法精确表示每个整数,前缀和会开始丢精度——本页的上限设置就是为避开这一点。 - 权重下限 0 而非 1:权重 0 是合法输入,语义是"这一项显示但不参与抽取"。全为 0 时页面直接报错,不允许除以零,也不允许"随机在全 0 的池子里选"这种无意义操作。
- 单项精度 2−32 = 2.328e−10:
u = v / 2³²把 uint32 映射到 [0, 1),最小可分辨差是 2.328e−10。这个粒度远小于 1/200 = 0.005(200 项等权时的单格概率),所以 200 项以内不存在"某格抽不到"的问题。 - 不放回模式的上限联动:抽取次数 k 超过参与项数 m 时,组合数 P(m, k) 无意义,页面直接报错并说明应该填多少,而不是悄悄少抽几个。m=4 抽 2 时 P(4,2) = 12 种有序组合、C(4,2) = 6 种无序组合;10 项全排列 10! = 3628800 种——所以不放回模式的"公平"和放回不同,前者保证每个选项恰好出现一次,后者给权重高的选项更多名额。
- 熵值里 p = 0 的处理:p log₂ p 在 p→0 时极限为 0,但直接算
0 * Math.log2(0)得到 NaN。页面跳过所有 p=0 的项——上表"1 : 0 : 0"那行熵值是干净的 0,不是 NaN。 - 长表与历史的渲染上限:抽取 200 次时历史序列有 200 个元素,全部渲染成文本会让
<pre>式的 DOM 变得很重。页面历史区显示最近 60 次并注明总数,完整记录用「导出 CSV」。
常见问题
权重填 1:1:1:1 和直接写"随机选一个"有什么区别?
算法上等价,行为上也等价——四项等权的熵正好是 log₂4 = 2.0000 bit,达到 100% 效率,分布完全均匀。区别在可审计:显式写成 1:1:1:1 意味着"我确认这四项一样重要",这个声明可以被别人检查、被后续修改、被复现。如果只写"随便选",权重就散落在代码各处,反而更不可控。
熵值低是不是说明我的权重设错了?
不是,熵低只说明分布集中,而集中有时候正是你要的。比如"十选一的问题里其实只有一个正确答案",设成 1000:1 让熵降到 0.0114 bit 反而是诚实的——它告诉你随机这一步已经不起作用了,该直接写死答案。熵值的作用是让你知道自己偏了多少,不是给你判对错。
不放回模式能不能保证"完全公平"?
它保证的是覆盖,不是概率公平。m 项不放回抽 k 个,每个选项被抽中的概率都是 k/m(等权时),而且每个选项最多出现一次——这是"每个人都能轮到"的意思。反过来,放回模式给高权重项更多名额,是"让权重起作用"的意思。想同时要覆盖和权重,需要设计成多轮放回,那已经不是本页的输入模型了。
我加了很多个几乎为零的权重项,会不会有问题?
不会,但要注意精度。权重是整数、页面上限是 100000,所以"几乎为零"实际就是 1。1 在权重和 20000000 里对应概率 5e−8,仍高于单步分辨率 2.328e−10,所以仍可分辨——真正会失效的是把权重和推过 253(= 9007199254740991),那时 float64 无法精确表示整数,前缀和开始丢精度,本页用 200 × 100000 的上限把它挡住了。200 项全设 1 时概率是 1/200 = 0.005,完全没问题。
为什么不用"随机打乱列表再取第一个",那样不是更简单?
Fisher–Yates 洗牌确实是"不放回抽取"的标准解法,本页在不放回模式下用的就是它。但放回模式下不能靠洗牌——洗牌会强制每个选项恰好出现一次,等于偷偷把权重抹平了。放回模式必须每次独立抽样并按权重比较,两者混用是常见的实现错误。所以本页把它们做成两个互斥的模式,切换时权重表会跟着变。
抽取次数填 12,看到某个选项中了 6 次,是不是权重设错了?
不是。权重 3 的项单次概率 37.5%,12 次里期望命中 4.5 次。6 次高于期望但在正常离散范围内——放回抽样服从二项分布,n=12、p=0.375 时出现 6 次完全常见。判断权重是否设错要看多次大样本:把次数调到 100 以上,命中比例会向 37.5% 收敛,那才是权重的真实体现。
CSV 导出为什么开头有一段看不见的字符?
那是 UTF-8 BOM(U+FEFF),3 字节。Excel 打开不带 BOM 的 UTF-8 CSV 会把中文识别成乱码,加上 BOM 就能正确识别编码。命令行工具(awk、cut)不会跳过它,会当成第一个字段的第一个字符——这是为了 Excel 用户做的刻意取舍,CSV 里那列内容本身也做了引号转义,逗号和换行不会串列。
这个工具免费吗?数据安全吗?
免费,无需注册即可使用。计算全部在浏览器内完成,不发任何网络请求,可在开发者工具 Network 面板自查(应为空)。选项内容不写入 localStorage,刷新即清空。