用S侧投掷N骰子时T总眼的概率

问题描述 投票:3回答:3

我想计算事件的概率,即n骰子与s边(从1到s编号)的所有眼睛的总和等于t。我的语言是Python 3。

我目前的方法几乎是一个尝试和计数的解决方案,只适用于小数字(运行probability(10, 10, 50)已经吃了我的所有内存并强迫我硬重置):

import itertools
def probability(n, s, t):
    all_rolls=list(itertools.product(range(1,s+1), repeat=n))
    target_rolls=[l for l in all_rolls if sum(l)==t]
    return round(len(target_rolls)/len(all_rolls), 4)

但老实说我不知道​​怎么解决这个问题。你能帮助我走上正轨吗?

python-3.x numpy probability dice
3个回答
1
投票

首先关闭:总可能的滚动组合将始终为s**n,因此您不需要存储所有可能性的列表以获得它的长度。类似地,你可以保持一个运行的所需结果总数,而不是保留它们的列表以节省内存空间,但它仍然不会加速该函数:

def probability(n, s, t):
    all_rolls = itertools.product(range(1,s+1), repeat=n) #no list, leave it a generator
    target_rolls=sum(1 for l in all_rolls if sum(l)==t) #just total them up
    return round(target_rolls/s**n, 4)

计算可能性的一种更有效的方法是使用dict和一些聪明的迭代。每个字典将使用roll值作为键,频率作为值,每次迭代prev将是前一个X骰子的dict,cur将通过添加另一个die来更新它:

import collections
def probability(n, s, t):
    prev = {0:1} #previous roll is 0 for first time
    for _ in range(n):
        cur = collections.defaultdict(int) #current probability
        for r,times in prev.items():
            for i in range(1,s+1):
                #if r occured `times` times in the last iteration then
                #r+i have `times` more possibilities for the current iteration.
                cur[r+i]+=times
        prev = cur #use this for the next iteration

    return cur[t] / s**n
    #return round(cur[t] / s**n , 4)

注1:因为cur是一个defaultdict,试图查找一个用给定输入不可能的数字将返回0

注意2:由于此方法将具有所有可能结果的字典放在一起,您可以返回cur并在同一个骰子卷上进行多个不同可能结果的计算。


1
投票

停止制作清单。只是使用懒惰的评估。

from itertools import product

def prob(dice, pips, target):
    rolls = product(range(1, pips+1), repeat=dice)
    targets = sum(1 for roll in rolls if sum(roll) == target)
    return targets / pips**dice

测试:

for i in range(5, 26):
    print(i, prob(5, 5, i))
print('sum: ', sum(prob(5, 5, i) for i in range(5, 26)))
# prints
5 0.00032
6 0.0016
7 0.0048
8 0.0112
9 0.0224
10 0.03872
11 0.0592
12 0.0816
13 0.1024
14 0.1168
15 0.12192  # symmetrical, with peak in middle
16 0.1168
17 0.1024
18 0.0816
19 0.0592
20 0.03872
21 0.0224
22 0.0112
23 0.0048
24 0.0016
25 0.00032
sum:  1.0000000000000002

编辑:删除未使用的def


1
投票

itertools.product太慢了,大量的边数> 5,边数> 6.在我的机器上有dice_number:10和边:10用了一个半小时来计算。相反,我使用numpy.polypow函数来计算目标,并且计算时间不到一秒。

from numpy.polynomial.polynomial import polypow

def probability(dice_number, sides, target):
    """
    Using numpy polynomial
    The number of ways to obtain x as a sum of n s-sided dice
    is given by the coefficients of the polynomial:

    f(x) = (x + x^2 + ... + x^s)^n
    """

    # power series (note that the power series starts from x^1, therefore
    # the first coefficient is zero)
    powers = [0] + [1] * sides
    # f(x) polynomial, computed used polypow in numpy
    poly = polypow(powers, dice_number)
    return poly[target] / sides ** dice_number if target < len(poly) else 0
© www.soinside.com 2019 - 2024. All rights reserved.