如何优化此计算

时间:2010-09-03 18:28:42

标签: optimization formula floating-accuracy

我正在编写一个模型检查器,它依赖于算法的计算,该系统由以下算法密集使用:

![alt text] [1]

其中q为double,t为double,k为int。 e代表指数函数。此系数用于以下步骤:qt不变,而k始终从0开始,直到所有先前系数(该步骤)的总和达到1。

我的第一个实现是文字的:

let rec fact k =
  match k with
    0 | 1 -> 1
    | n -> n * (fact (k - 1))

let coeff q t k = exp(-. q *. t) *. ((q *. t) ** (float k)) /. float (fact k)

当然,这并没有持续太久,因为当k超过一个小门槛(15-20)时,计算整个阶乘是不可行的:显然结果开始变得疯狂。所以我通过增量划分来重新安排整个事情:

let rec div_by_fact v d =
  match d with
    1. | 0. -> v
    | d -> div_by_fact (v /. d) (d -. 1.)

let coeff q t k = div_by_fact (exp(-. q *. t) *. ((q *. t) ** (float k))) (float k)

qt足够'正常'但事情变得奇怪时,例如q = 50.0t = 100.0并且我开始从k = 0 to 100我得到的是一系列0,后跟一定数量的NaN直到结束。

当然,这是由数字开始接近0或类似问题的操作引起的。

您是否知道我如何优化公式,以便能够在广泛的输入范围内提供足够准确的结果?

一切都应该是64位(因为我使用的是默认使用双精度的OCaml)。也许有一种方法可以使用128位双打,但我不知道如何。

我正在使用OCaml,但你可以用你想要的任何语言提供想法:C,C ++,Java等。我很好地使用了它们。

2 个答案:

答案 0 :(得分:3)

qt^k/k! = e^[log[qt^k/k!]]
log[qt^k/k!] = log[qt^k] - log[k!] // log[k!] ~ klnk - k  by stirling
             ~ k ln(qt) - (k lnk - k)
             ~ k ln(qt/k) - k

对于小的k值,斯特林近似不准确。 但是,由于您似乎在进行有限的已知范围,因此您可以计算log[k!]并将其放入数组中,从而避免任何错误。

当然,您可以进一步做出多种变化。

答案 1 :(得分:1)

这不是一个答案(我相信),但这只是一个澄清。如果我误解了某些内容,我会在你发表评论后将其删除。

据我了解,您正在尝试计算n,例如以下总和等于1.

alt text

正如你可能看到渐近地接近1,它永远不会等于1。 如果我误解了你的问题,请纠正我。