在C ++中工作,我想找到一些数量的总和,然后记录总和的日志:
log(a_1 + a_2 + a_3 + ... + a_n)
但是,我自己没有数量,我只有他们的记录值:
l_1 = log(a_1), l_2 = log(a_2), ... , l_n = log(a_n)
有没有有效的方法来获取日志a_i的总和?我想避免
log(s) = log(exp(l_1) + exp(l_2) + ... + exp(l_n))
如果可能的话 - exp会成为瓶颈,因为计算已多次完成。
答案 0 :(得分:3)
我不知道任何方式,因为,一般来说,没有办法计算
e x + e y
使用加法,只有一次取词,这相当于你所要求的。
正如FrédéricHamidi上面的评论所提到的,即使你对指数进行求和,你还有另一个需要担心的问题:溢出。 link he gave提供了一个非常好的解决方案(从该链接复制的Fortran代码之后):
function log_sum_exp(v) result(e)
real, dimension(:), intent(in) :: v ! Input vector
real :: e ! Result is log(sum(exp(v)))
real :: c ! Shift constant
! Choose c to be the element of v that is largest in absolute value.
if ( maxval(abs(v)) > maxval(v) ) then
c = minval(v)
else
c = maxval(v)
end if
e = log(sum(exp(v-c))) + c
end function log_sum_exp
答案 1 :(得分:3)
n有多大?
这个数量被称为log-sum-exp,而Lieven Vandenberghe在他的book的第72页上对此进行了讨论。他还有optimization package使用这个操作,从简短的看,似乎他没有做任何特殊的操作,只是指数和补充。当n足够小以使向量适合记忆时,取幂可能不是一个严重的瓶颈。
这种操作经常出现在建模中,而且瓶颈存在大量的术语。 n = 2 ^ 100的幅度是常见的,其中隐含地表示术语。在这种情况下,依赖于log-sum-exp的凸性,有各种技巧可以近似这个数量。最简单的技巧 - 近似log(s)为max(l1,l2,....,ln)
答案 2 :(得分:1)
您可以使用以下身份:
log( a + b ) = log(a) + log( 1 + (b/a) )
答案 3 :(得分:1)
它不是很优雅,但您可以尝试以下方法。
lg a_i
获取log a_i
(除以log 2
)。lg a_i
= k
+ q
其中k
为整数,q
为真,0 >= q >= 1
a_i
2 k pow(2,q)
(使用位移2 k = 1 << k
)。pow(2,q)
所以整个想法是利用快速2次幂功能。希望它有所帮助!
答案 4 :(得分:1)
如果s_k:= sum(a_1 + ... + a_k)
那么
s_ {k + 1} == s_k + f(l_{k+1} - s_k)
,其中
f(x) := log(1+exp(x))
这个函数f
可以用泰勒级数或类似函数计算,速度可与exp
相媲美,甚至可能内联。
这只能节省两个数学函数,但它可能是一个有用的起点。