1

我想计算日志( exp(A1) + exp(A2) )。
下面的公式

 log(exp(A1) + exp(A2) ) = log[exp(A1)(1 + exp(A2)/exp(A1))] = A1 + log(1+exp(A2-A1)) 

当 A1 和 A2 很大并且数值为 exp(A1)=Inf(或 exp(A2)=Inf)时很有用。(这个公式在这个线程中讨论 -> 如何从其组件 log-terms 计算 log(sum of terms))。当 A1 和 A2 的角色被替换时,公式为真。

我对这个公式的关注是当 A1 和 A2 非常小时。例如,当 A1 和 A2 是:

 A1 <- -40000
 A2 <- -45000

那么 log(exp(A1) + exp(A2) ) 的直接计算是:

 log(exp(A1) + exp(A2))
 [1] -Inf

使用上面的公式给出:

 A1 + log(1 + exp(A2-A1))
 [1] -40000

这是A1的值。将上面的公式与 A1 和 A2 的翻转角色一起给出:

A2 + log(1 + exp(A1-A2))
[1] Inf

这三个值中哪个最接近 log(exp(A1) + exp(A2)) 的真实值?是否有稳健的方法来计算 log(exp(A1) + exp(A2)) 可以在 A1、A2 较小且 A1、A2 较大时使用。

先感谢您

4

2 回答 2

3

您应该使用更准确的东西来进行直接计算。

它“在 [它们] 很大时没有用”。当差异非常负时,它很有用。

x接近 0 时,则log(1+x)大约为x。因此,如果A1>A2,我们可以采用您的第一个公式:

log(exp(A1) + exp(A2)) = A1 + log(1+exp(A2-A1))

并将其近似为A1 + exp(A2-A1)(并且近似值会变得更好,因为A2-A1它更负)。由于A2-A1=-5000,这足以使近似值足够负。

无论如何,如果y离零太远(无论哪种方式)exp(y)都会(溢出|低于)双精度并导致 0 或无穷大(这是双精度,对吧?你使用什么语言?)。这解释了你的答案。但由于exp(A2-A1)=exp(-5000)接近于 0,你的答案大约是-40000+exp(-5000),这与 没有区别-40000,所以一个是正确的。

于 2014-10-18T05:06:40.487 回答
1

在如此巨大的指数差异中,您可以在没有任意精度的情况下做的最安全的是

  • 选择了最大的指数让它成为Am = max(A1,A2)
  • 所以:log(exp(A1)+exp(A2)) -> log(exp(Am)) = Am
  • 这是您在这种情况下可以获得的最接近的
  • 所以在你的例子中,结果是-40000+delta
  • 其中 delta 非常小

如果您想使用第二个公式,那么一切都分解为计算log(1+exp(A))

  • 如果A为正,则结果与真实情况相去甚远
  • 如果A是负数,那么它将被截断,log(1)=0所以你得到与上面相同的结果

[笔记]

  • 你的指数差是base^500
  • 单精度 32 位浮点数最多可存储数字(+/-)2^(+/-128)
  • 双精度 64 位浮点数最多可存储数字(+/-)2^(+/-1024)
  • 因此,当您的基数为 10 或 e 时,这远远不够您所需要的
  • 如果你有四倍的精度应该足够了,但是当你再次开始改变 exp 差异时,你将很快达到与现在相同的点

[PS] 如果您需要更高的精度而不需要任意精度

  • 你可以尝试创建自己的号码类
  • 内部存储数字,例如number=a^b
  • 其中 a,b 是浮点数
  • 但为此,您需要编写所有基本功能
  • *,/简单
  • +,-是一场噩梦,但即使为此也可能有一些方法/算法
于 2014-10-18T05:18:06.860 回答