Як надійно додати великі експоненціальні доданки без помилок переповнення?


24

Дуже поширена проблема ланцюга Маркова в Монте-Карло включає обчислення ймовірностей, які є сумою великих експоненціальних доданків,

еа1+еа2+...

аК: =максi(аi)

а'=К+лог(еа1-К+еа2-К+...)
еа'еа1+еа2+...

Цей підхід є розумним, якщо всі елементи є великими, але це не дуже гарна ідея, якщо вони не є. Звичайно, більш дрібні елементи ніяк не вносять до суми з плаваючою комою, але я не впевнений, як з ними надійно боротися. У R-коді мій підхід виглядає так:а

if ( max(abs(a)) > max(a) )
  K <-  min(a)
else
  K <- max(a)
ans <- log(sum(exp(a-K))) + K

Здається, досить поширеною проблемою є те, що має бути стандартне рішення, але я не впевнений, що це таке. Дякуємо за будь-які пропозиції.


1
Це річ. Google для 'logsumexp'.

Відповіді:


15

Є просте рішення з лише двома пропусками даних:

Перший обчислити

К: =максiаi,

який говорить вам , що, якщо є терми, то Σ я е яп е К .н

iеаiнеК.

Так як ви , ймовірно , не мають ніде поблизу , як великий , так як навіть 10 20 , ви не повинні мати турбуватися про переповненості в обчисленні т : = Σ я е я - KN з подвійним точністю.н1020

τ: =iеаi-Кн

Таким чином, обчисліть і тоді ваше рішення - e K τ .τеКτ


Дякую за чітке нотацію - але я вважаю , що це по суті те , що я запропонував Якщо мені потрібно , щоб уникнути помилок під час Underflow деяких (?) Я маленькі, я розумію , мені потрібен підсумовування підхід Кахана запропонований @gareth ? аi
cboettig

Ах, тепер я бачу, до чого ти потрапив. Насправді не потрібно турбуватися про перетікання, оскільки додавання виключно крихітних результатів до рішення не повинно змінювати його. Якщо їх було надзвичайно велика кількість, то спершу слід підсумувати невеликі значення.
Джек Поульсон

Клієнту: чи не заперечуєте ви повідомити мені, що не так у моїй відповіді?
Джек Поульсон

що робити, якщо у вас багато дуже маленьких термінів? Може статися, що для них . Якщо таких термінів багато, ви мали би велику помилку. еаi-К0
бекко


10

Щоб зберегти точність, коли ви додаєте парні разом, вам потрібно використовувати підсумовування Kahan , це програмне забезпечення, еквівалентне реєстрації переноски.

е709.783doubleMax - sumSoFar < valueToAddexponent > 709.783

vалуе×2сгодifт

#!/usr/bin/env python
from math import exp, log, ceil

doubleMAX = (1.0 + (1.0 - (2 ** -52))) * (2 ** (2 ** 10 - 1))

def KahanSumExp(expvalues):
  expvalues.sort() # gives precision improvement in certain cases 
  shift = 0 
  esum = 0.0 
  carry = 0.0 
  for exponent in expvalues:
    if exponent - shift * log(2) > 709.783:
      n = ceil((exponent - shift * log(2) - 709.783)/log(2))
      shift += n
      carry /= 2*n
      esum /= 2*n
    elif exponent - shift * log(2) < -708.396:
      n = floor((exponent - shift * log(2) - -708.396)/log(2))
      shift += n
      carry *= 2*n
      esum *= 2*n
    exponent -= shift * log(2)
    value = exp(exponent) - carry 
    if doubleMAX - esum < value:
      shift += 1
      esum /= 2
      value /= 2
    tmp = esum + value 
    carry = (tmp - esum) - value 
    esum = tmp
  return esum, shift

values = [10, 37, 34, 0.1, 0.0004, 34, 37.1, 37.2, 36.9, 709, 710, 711]
value, shift = KahanSumExp(values)
print "{0} x 2^{1}".format(value, shift)

Підсумовування Кахана - це лише один із сімейства методів "компенсованого підсумовування". Якщо з якоїсь причини Кахан не працює цілком правильно, існує ряд інших методів правильного складання термінів різної величини та протилежних знаків.
JM

@JM ви могли б надати мені назви цих інших методів, мені було б дуже цікаво їх прочитати. Спасибі.
Гарет А. Ллойд


0

Існує пакет R, який забезпечує швидку та ефективну реалізацію "трюк log-sum-exp"

http://www.inside-r.org/packages/cran/matrixStats/docs/logSumExp

Функція logSumExp приймає числовий вектор lX і виводить журнал (sum (exp (lX))), уникаючи при цьому проблем з переливом і переливом, використовуючи описаний вами метод.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.