You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RPG骰子高数值场景下概率计算代码异常问题排查

骰子投掷成功概率计算函数bug排查

问题背景

我编写了calc_dados函数用于计算骰子投掷的成功概率,小数值场景下运行正常,但大数值场景下结果异常。通过pandas生成模拟硬币(2面骰子)的概率表时,发现结果与暴力测试的正确结果不符——例如4枚硬币至少出现1次正面的正确概率为93.75%,但函数输出为81.25%,请求协助排查问题原因。

原函数代码:

def calc_dados(f_sucessos = 1, faces = 6, n_dados = 1):

  p_max = ((f_sucessos/faces)**n_dados) #chance de todos

  fator = 1
  p_meio = 0

  for i in range(n_dados-1):
    p_meio += (((f_sucessos/faces)**(n_dados-fator) * ((faces-f_sucessos)/faces)**(n_dados-(n_dados-fator))) * n_dados)
    fator += 1

  p = p_max + p_meio
  return p*100

测试代码:

import pandas as pd

f_sucessos = 1    # 成功面数
faces = 2         # 骰子总面数
n_dados = 10      # 投掷骰子数量

suc_list = []
for i in range(0,n_dados): suc_list.append(f_sucessos)
fac_list = []
for i in range(0,n_dados): fac_list.append(faces)
cha_list = []
for i in range(0,n_dados): cha_list.append(calc_dados(f_sucessos, faces, i+1))

df = pd.DataFrame(
{
"n_dados" : range(1,n_dados+1),
"faces" : fac_list,
"sucessos" : suc_list,
"chance" : cha_list
 }
)
df

问题原因

函数核心逻辑存在两处关键错误:

  • 概率项构造错误:循环中成功/失败次数的对应关系混乱,((faces-f_sucessos)/faces)**(n_dados-(n_dados-fator))简化后是失败次数为fator、成功次数为n_dados-fator,这和「至少1次成功」需要覆盖的1到n次成功的情况完全不匹配。
  • 组合数错误:直接用n_dados作为每个概率项的系数,但实际上每种「k次成功、n-k次失败」的情况对应的组合数是从n个骰子中选k个的组合数C(n,k),而非固定的n。

以n=4为例,原函数计算的是「4次成功」+「3次成功1次失败」*4 +「2次成功2次失败」*4,完全遗漏了「1次成功3次失败」的情况,结果自然偏差。

修正方案

方案1:补集法(推荐,高效不易错)

计算「至少1次成功」的概率,最简便的方法是用1减去「全失败」的概率:

def calc_dados(f_sucessos=1, faces=6, n_dados=1):
    # 单次骰子失败的概率
    p_single_fail = (faces - f_sucessos) / faces
    # 所有骰子都失败的概率
    p_all_fail = p_single_fail ** n_dados
    # 至少1次成功的概率 = 1 - 全失败概率
    p_success = 1 - p_all_fail
    return p_success * 100

方案2:修正原逻辑(直接枚举所有成功情况)

如果坚持要用原思路枚举所有成功情况,需要引入组合数计算(Python 3.10+支持math.comb):

import math

def calc_dados(f_sucessos=1, faces=6, n_dados=1):
    p_single_success = f_sucessos / faces
    p_single_fail = 1 - p_single_success
    total_prob = 0
    # 遍历1次成功到n_dados次成功的所有情况
    for k in range(1, n_dados + 1):
        # 组合数:从n个骰子中选k个成功的情况数
        comb_count = math.comb(n_dados, k)
        # 当前情况的概率:组合数 * 成功概率^k * 失败概率^(n-k)
        case_prob = comb_count * (p_single_success ** k) * (p_single_fail ** (n_dados - k))
        total_prob += case_prob
    return total_prob * 100

验证结果

用n=4测试,两种修正后的函数都会返回93.75%,符合正确结果;测试n=10时,也能得到正确的「至少1次正面」概率99.90234375%。

内容的提问来源于stack exchange,提问作者Daniel Capua

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 20:25:31