-5

有什么方法可以编写一个功能上等同于这个函数而不包含循环的函数?

Python代码:

luck = 0.3
tries = 200000000

getStrikes():
    strikes = 0
    for i in range(tries):
        if random.random() <= luck:
            strikes++;
    return strikes

好的,抱歉,我在过去 5 分钟内一直在对原始帖子进行垃圾邮件编辑。我现在要停下来,因为我已经根据收到的反馈澄清了我想问的问题。

4

2 回答 2

3

strikes是一个二项分布的随机变量。scipy比对大量伯努利试验求和更有效地支持从该分布中抽样。

这是一个例子:

from scipy.stats import binom

luck = 0.3
trials = 200000000
print binom(trials, luck).rvs()

尽管进行了大量试验,但这几乎是立即运行的。

于 2016-07-27T00:16:01.510 回答
2

在函数式编程中有几个工具可以做到这一点,比如折叠和列表/生成器推导,但最基本的想法是递归。

因此,例如,对于 getTotal():

getTotal(sides, dice):
    if dice == 0:
        return 0
    else
        return rand.int(sides) + getTotal(sides, dice - 1)

遗憾的是,此函数不适用于您的特定示例,因为堆栈将在我们到达结束之前很久就溢出。我们通过使函数尾递归来解决这个问题,因此您可以使用尾调用优化(并非所有语言都使用此功能,但几乎所有函数式语言都使用)。这是通过添加一个以 0 开头的累加器变量来实现的:

getTotal(sides, dice, accumulator = 0):
    if dice == 0:
       return accumulator
    else
       return getTotal(sides, dice - 1, accumulator + rand.int(sides))

在这个版本的函数中,递归调用是一个“尾调用”,这意味着它是函数做的最后一件事(在以前的版本中不是这种情况,加法是最后发生的事情,所以它不是尾递归)。版本可以以相同的getSixes()方式完成,除了不只是将掷骰子添加到累加器中,当且仅当掷骰为 6 时,我们才将 1 添加到累加器中。

但是,这种模式很常见,以至于许多语言都有“快捷方式”,即fold。因为我不想发明一堆符号,所以我将用 Python 编写下一个示例:

def getTotal(sides, dice):
    add = lambda x,y: x + y
    return reduce(add, (rand.int(sides) for _ in range(dice)))

reduce是 python 的左折叠名称,add是我们要折叠的函数。该(rand.int(sides) for _ in range(dice))部分是一个生成器,它会懒惰地(即我们需要它们,而不是一开始就一次)生成你的随机数,特别dice是它们的数量。

函数式编程的另一个技巧是根据一些布尔函数“过滤”值。我们可以getSixes()这样解决:

def getSixes(sides, dice):
    condition = lambda x: x == 6
    return len(filter(condition, (rand.int(sides) for _ in range(dice))))

所有这些方式都具有与使用循环相同的内存/速度特性(即相同的 big-O 特性),尽管使用循环通常会更快一些,因为开销较小。

编辑:这个答案更多地适用于您编辑之前的问题版本,但这个想法与您的新版本非常相似。

编辑2:原标题是“你如何在不使用循环的情况下重写这个问题”,这就是我的回答所适用的,如何在不使用循环的情况下做到这一点。我没有意识到你想要一个数学公式,为什么我的答案根本不适用。

于 2016-07-27T00:15:36.860 回答