有效地汇总日志数量

时间:2011-02-04 22:44:15

标签: c++ algorithm math sum probability

在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会成为瓶颈,因为计算已多次完成。

5 个答案:

答案 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)。
  • 您可以使用[0,1]
  • 的有限精度的预计算表加快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相媲美,甚至可能内联。

这只能节省两个数学函数,但它可能是一个有用的起点。