Java实现Monty Hall问题模拟结果异常:0.61而非预期0.66求排查
蒙提霍尔问题代码错误排查
你的代码核心问题是在循环内部每次迭代都创建新的SecureRandom实例,这会导致随机数生成的随机性严重不足,进而引发概率计算偏差。
SecureRandom的初始化依赖系统熵池获取随机种子,频繁创建实例会导致种子重复或熵值不足,生成的随机数序列会出现偏向(比如玩家初始选择的门和正确门的重合概率高于理论的1/3),最终使得换门后的中奖概率低于预期的2/3。
修复后的代码
将SecureRandom的创建移到循环外部,确保整个测试过程使用同一个随机数生成器:
public static double MontyHall(int numTests) { int passedTests = 0; SecureRandom random = new SecureRandom(); // 移到循环外,仅初始化一次 for(int i = 0; i < numTests; ++i) { List<Integer> puertas = new ArrayList<>(Arrays.asList(0,0,0)); //0wrong door, 1right door, -1opened door int rightDoor = random.nextInt(3); puertas.set(rightDoor, 1); int choice = random.nextInt(3); if(rightDoor == choice) { int aux = random.nextInt(2); for(int k = 0; k < puertas.size(); ++k) { if(k != rightDoor && aux == 0) { puertas.set(k, -1); } else if(k != rightDoor) --aux; } } else { for(int j = 0; j < puertas.size(); ++j) { if(j != rightDoor && j != choice) puertas.set(j, -1); } } for(int l = 0; l < puertas.size(); ++l) { if(l != choice && puertas.get(l) != -1) choice = l; } if(puertas.get(choice) == 1) ++ passedTests; } return (double) passedTests / numTests; }
验证结果
修改后运行100000次迭代,结果会接近理论值0.666左右,比如:
0.66589 0.66712 0.66603
额外优化建议
可以简化门的状态管理,不需要用List,直接用变量记录即可,减少不必要的集合操作:
// 替代List的简化逻辑:只需要记录正确门、初始选择、打开的门,不需要维护所有门的状态 int rightDoor = random.nextInt(3); int choice = random.nextInt(3); int openedDoor; if (rightDoor == choice) { // 随机选一个错误门打开 do { openedDoor = random.nextInt(3); } while (openedDoor == rightDoor); } else { // 打开既不是正确门也不是初始选择的门 openedDoor = 3 - rightDoor - choice; } // 换门:选择既不是初始选择也不是打开的门 choice = 3 - choice - openedDoor;
这种写法更简洁,也避免了集合操作可能带来的潜在问题。
内容的提问来源于stack exchange,提问作者BleachEnjoyer
相关产品推荐
相关产品推荐

