Skip to content

随机抽取代码存在缺陷 #142

@fivegg

Description

@fivegg

for (let i = 0; i < luckyCount.value; i++) {
if (personPool.value.length > 0) {
const randomIndex = Math.floor(Math.random() * (personPool.value.length - 1))
luckyTargets.value.push(personPool.value[randomIndex])
personPool.value.splice(randomIndex, 1)
}
}这段抽奖代码是否存在随机元素概率过于不均等问题?
ai回复:这段抽奖代码存在严重的概率不均等问题,甚至会导致部分元素永远无法被抽中,核心问题出在随机索引的计算逻辑上。以下是详细分析和修复方案:
一、核心问题:随机索引范围错误(最致命)
代码中 Math.floor(Math.random() * (personPool.value.length - 1)) 是关键错误:
Math.random() 返回 [0, 1) 区间的随机数;
乘以 length - 1 后,随机数范围是 [0, length - 1);
经 Math.floor() 处理后,最终索引范围是 [0, length - 2]。
这意味着:数组最后一个元素(索引 length - 1)永远不会被选中,直接导致该元素的中奖概率为 0;而其他元素的概率也会因为「每次漏掉最后一个」出现不均。
举个例子(直观验证)
假设 personPool = [A, B, C](length = 3):
随机索引范围是 0 ~ 1(因为 3-1=2,Math.random()*2 → 0~2 → floor 后 0/1);
元素 C(索引 2)永远抽不到;
第一次抽奖只能选 A/B,抽中后删除,第二次若剩 B/C,依然只能选 B(索引 0),C 还是抽不到。
二、次要问题:极端场景下的索引越界(潜在风险)
当 personPool.length = 1 时,length - 1 = 0,Math.random() * 0 = 0,索引为 0(刚好有效);但如果代码逻辑变动(比如先减长度再计算),会导致 length - 1 = -1,此时随机索引为负数,直接报错。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions