鉴于log(a)
和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
和numpy
计算log(a+b)
的标准log(a)
或log(b)
函数?
如果没有,你知道为这个函数制作单个C ++钩子的简单方法吗?它不是一个复杂的函数(它使用浮点数),正如我所说,它占据了我运行时的大部分时间。
先谢谢,数字方法忍者!
答案 0 :(得分:9)
注意:到目前为止,最好的答案是使用numpy.logaddexp(logA,logB)
。
为什么要与log(0)
进行比较?这等于-numpy.inf
,在这种情况下,您来到log(1 + math.exp(-inf-logB) ) + logB
,这会将自身缩减为logB。此调用始终会发出一条极其缓慢的警告消息。
我可以想出这个单行。但是,你需要真正测量,看看这实际上是否更快。它只使用一个“复杂”计算函数而不是你使用的两个,并且没有发生递归,if
仍然存在,但在fabs
/ {{1}中隐藏(并且可能已经优化) }}
maximum
编辑:
我做了一个快速的timeit(),结果如下:
def log_add(logA,logB):
return numpy.logaddexp(0,-numpy.fabs(logB-logA)) + numpy.maximum(logA,logB)
,但如果它已经下降到18秒,那么它也适用于你的递归。更新了代码,您也可以使用内联更新公式切换递归调用,但这对我的时序测试没什么影响:
logaddexp
编辑2:
正如pv在评论中指出的那样,实际上你可以def log_add2(logA, logB):
if logA < logB:
return log_add2(logB, logA)
return numpy.logaddexp(0,logB-logA)+logA
来计算numpy.logaddexp(logA, logB)
,这当然等于log(exp(logA)+exp(logB))
。我计时(在上面的同一台机器上),它进一步下降到大约10秒。所以我们已经下降到大约1/12,不差;)。
答案 1 :(得分:-1)
def log_add(logA, logB):
return math.log(math.exp(logA) + math.exp(logB))
太慢了?还是不准确?