通过日志

时间:2017-05-13 08:16:49

标签: algorithm precision logarithm

来源:Google Code Jam。 https://code.google.com/codejam/contest/10224486/dashboard#s=a&a=1

我们被要求计算Prob(来自N次试验的K次成功),其中N次试验中的每一次都具有已知的p_n成功概率。

在Code Jam之后给出了一些关于这个问题的分析和想法。

他们观察到,评估N次试验的所有可能结果将使你在N中呈指数级时间,因此它们提供了一个很好的“动态编程”式解决方案,即O(N ^ 2)。

设P(p#q)= Prob(p在第一次q试验后成功) 然后观察以下事实:

Prob(p#q) = Prob(qth trial succeeds)*P(p-1#q-1) + Prob(qth trial fails)*P(p#q-1)

现在我们可以建立一个P(i#j)表,其中i <= j,i = 1 ... N

这一切都很可爱 - 我遵循所有这些并且可以实现它。

然后作为最后一条评论,他们说:

In practice, in problems like this, one should store the logarithms of
probabilities instead of the actual values, which can become small
enough for floating-point precision errors to matter.

我认为我广泛理解他们想要表达的观点,但我特别无法弄清楚如何使用这个建议。

采用上述等式,并在一些字母变量中进行替换:

P = A*B + C*D

如果我们想在Log Space中工作,那么我们有:

Log(P) = Log(A*B + C*D),

我们以递归方式预先计算Log(B)Log(D)以及A&amp; B是已知的,易于处理的小数。

但是我没有看到任何方法来计算Log(P)而不仅仅做e^(Log(B))等等,感觉它会在日志空间中失败?

有没有人更清楚地了解我应该做什么?

1 个答案:

答案 0 :(得分:6)

从最初的关系开始:

P =A⋅B+C⋅D

由于其对称性,我们可以假设B大于D,而不失一般性。 以下处理非常有用:

log(P)= log(A⋅B+ C * D)= log(A⋅e log(B) +C⋅e log(D) )= log(e log(B)·(A +C⋅e log(D) - log(B)

log(P)= log(B)+ log(A +C⋅e log(D) - log(B))。

这很有用,因为在这种情况下,log(B)和log(D)都是负数(某些概率的对数)。假设B大于D,因此其log更接近零。因此log(D) - log(B)仍为负数,但不如log(D)那样负。

所以现在,我们不需要分别执行log(B)和log(D)的取幂,而只需要执行log(D) - log(B)的取幂,这是一个温和的负数。因此,上述处理导致更好的数值行为,而不是使用对数和以平凡的方式应用求幂,或者等效地,而不是完全不使用对数。