6

给定log(a)and log(b),我想计算log(a+b)(以数值稳定的方式)。

我为此写了一个小函数:

def log_add(logA,logB):
    if logA == log(0):
        return logB
    if logA<logB:
        return log_add(logB,logA)
    return log( 1 + math.exp(logB-logA) ) + logA

我写了一个程序,这是迄今为止最耗时的一段代码。显然我可以尝试优化它(例如,消除递归调用)。

你知道从和计算的标准math或函数吗?numpylog(a+b)log(a)log(b)

如果没有,您是否知道为该函数制作单个 C++ 挂钩的简单方法?这不是一个复杂的函数(它使用浮点数),正如我所说,它占用了我运行时的大部分时间。

在此先感谢数值方法忍者!

4

2 回答 2

8

注意:到目前为止,最好的答案是简单地使用numpy.logaddexp(logA,logB).

为什么要与 比较log(0)?这等于-numpy.inf,在这种情况下,您log(1 + math.exp(-inf-logB) ) + logB将自己归结为 logB。这个调用总是会给出一个非常慢的警告消息。

我可以想出这个单线。但是,您需要真正测量以查看这是否实际上更快。它只使用一个“复杂”计算函数而不是您使用的两个,并且没有发生递归,if它仍然存在但隐藏(并且可能优化)在fabs/中maximum

def log_add(logA,logB):
    return numpy.logaddexp(0,-numpy.fabs(logB-logA)) + numpy.maximum(logA,logB)

编辑:

我做了一个快速 timeit() ,结果如下:

  1. 您的原始版本大约需要 120 秒
  2. 我的版本花了大约 30 秒
  3. 我从您的版本中删除了与 log(0) 的比较,它下降到 20 秒
  4. 我编辑了我的代码以保留它,logaddexp但也与你的递归 if 一起工作,它下降到 18 秒。

更新了代码,您还可以使用内联更新公式切换递归调用,但这对我的计时测试几乎没有影响:

def log_add2(logA, logB):
    if logA < logB:
        return log_add2(logB, logA)
    return numpy.logaddexp(0,logB-logA)+logA

编辑2:

正如 pv 在评论中指出的那样,您实际上可以做numpy.logaddexp(logA, logB)这归结为计算log(exp(logA)+exp(logB))哪个当然等于log(A+B). 我对它进行了计时(在与上面相同的机器上),它进一步下降到大约 10 秒。所以我们已经下降到大约 1/12,还不错;)。

于 2011-09-20T07:05:15.070 回答
-1
def log_add(logA, logB): 
    return math.log(math.exp(logA) + math.exp(logB))

太慢了?或不准确?

于 2011-09-20T07:05:10.973 回答