2014-10-18 8 views
0

Я хотел бы вычислить log (exp (A1) + exp (A2)).
Приведенная ниже формулаРасчет журнала (сумма exp (термины)), когда «термины» очень малы

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

полезна, когда А1 и А2 являются большими и численно ехр (А1) = Inf (или ехр (А2) = Inf). (эта формула обсуждается в этой теме -> How to calculate log(sum of terms) from its component log-terms). Формула верна, когда роль A1 и A2 заменяются.

Моя озабоченность этой формулой заключается в том, что A1 и A2 очень малы. Например, когда A1 и A2:

A1 <- -40000 
A2 <- -45000 

то непосредственное вычисление бревна (ехр (А1) + ехр (А2)) составляет:

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

Используя формулу выше, дает:

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

который является значением A1. Изинга формулу выше с перевернутым роли А1 и А2 дает:

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

Какой из трех значений ближе всего к истинному значению лога (ехр (А1) + ехр (А2))? Существует ли надежный способ вычисления log (exp (A1) + exp (A2)), который может использоваться как при A1, A2, так и в A1, A2 больших.

Спасибо заранее

ответ

1

в таком огромном показателе различии самого безопасном вы можете обойтись без произвольной точности является

  • выбрал самый большой показатель пусть это будет Am = max(A1,A2)
  • так: log(exp(A1)+exp(A2)) -> log(exp(Am)) = Am
  • , что ближайшее вы можете получить за такие case
  • поэтому в вашем примере результат -40000+delta
  • где дельта что-то очень маленькое

Если вы хотите использовать вторую формулу, то все распадается на вычисления log(1+exp(A))

  • если A является положительным, то результат будет далек от реальной вещи
  • если A является отрицательным, то оно будет усечение чтобы log(1)=0 так что вы получите тот же результат, как и в выше

[Примечания]

  • ваша разница экспонента base^500
  • одинарной точности 32bit поплавок может хранить числа до (+/-)2^(+/-128)
  • двойной точности 64bit поплавок может хранить числа до (+/-)2^(+/-1024)
  • так, когда ваша база 10 или е, то это не достаточно близко, что вам нужно
  • если у вас четвероносная точность, которой должно быть достаточно, но когда вы начнете менять разницу в экспорте снова, вы быстро достигнете той же точки, что и сейчас.

[PS], если вам нужно больше точности без произвольной точности

  • вы можете попробовать создать собственный номер класса
  • с внутренним запасом чисел как number=a^b
  • где а, Ь плавает
  • , но для этого вам необходимо будет указать все основные функции
  • *,/ легко
  • +,- - это кошмар, но там могут быть некоторые подходы/алгоритмы, даже для этого
1

Вы должны использовать что-то с большей точностью, чтобы сделать прямой расчет.

Это не «полезно, когда [они] большие». Это полезно, когда разница очень отрицательная.

Когда 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) близок к нулю, ваш ответ примерно -40000+exp(-5000), который неотличим от -40000, так что один из них правильный.