Taşma hataları olmadan büyük üstel terimler güvenilir şekilde nasıl eklenir?


24

Markov Zincirinde çok yaygın bir sorun olan Monte Carlo, büyük üstel terimlerin toplamı olan hesaplama olasılıklarını içermektedir.

ea1+ea2+...

Bir kutudaki bileşenler çok küçükten çok geniş yelpazeye kadar değişebilir. Benim yaklaşımım, en büyük üstel terimi etmektir, böylece:aK:=maxi(ai)

e bir 'E bir 1 + e bir 2 + . . .

a=K+log(ea1K+ea2K+...)
eaea1+ea2+...

Bu yaklaşım tüm unsurları eğer makul a onlar değilse kadar iyi bir fikir büyük, ancak. Tabii ki, daha küçük elemanlar kayan nokta toplamına hiçbir şekilde katkıda bulunmuyor, ancak onlarla nasıl güvenilir bir şekilde başa çıkılacağından emin değilim. R kodunda yaklaşımım şöyle gözüküyor:

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

Standart bir çözüm olması gereken yeterince yaygın bir sorun gibi görünüyor, ancak ne olduğundan emin değilim. Herhangi bir öneriniz için teşekkür ederiz.


1
Bu bir şey. 'Logsumexp' için Google.

Yanıtlar:


15

Verilerde yalnızca iki geçişli basit bir çözüm var:

İlk hesaplama

K:=maxiai,

size terimleri varsa, o zaman Σ i e bir in e K .n

ieaineK.

Muhtemelen kadar bile yakın hiçbir yerde olmadığına göre, hesaplamasında çift ​​kesinlikli taşma konusunda endişelenmenize gerek yoktur .10 20 τ : = i a a i - Knn1020

τ:=ieaiKn

Böylece, hesaplayın ve sonra çözüm .e K ττeKτ


Net gösterim için teşekkürler - ama bunun temelde önerdiğim şey olduğuna inanıyorum (?) Bazı küçükken taşma hatalarından kaçınmam gerekiyorsa, @gareth'in önerdiği Kahan toplama yaklaşımına ihtiyacım var ? ai
cboettig

Ah, şimdi neye bulaştığını anladım. Gerçekte alttan akış için endişelenmenize gerek yok, çünkü çözümünüze son derece küçük sonuçlar eklemek bunu değiştirmemelidir. İstisnai olarak çok sayıda varsa, önce küçük değerleri toplamalısınız.
Jack Poulson

Downvoter'a: Cevabımın neyin yanlış olduğunu bilmeme izin verir misin?
Jack Poulson

ya çok çok küçük terimleriniz varsa? Bunlar için . Bunun gibi birçok terim varsa, büyük bir hata olur. eaiK0
becko


10

Birlikte çiftler eklerken hassasiyetini korumak için Kahan Summation kullanmanız gerekir , bu bir taşıma kaydına sahip olan yazılımdır.

e709.783doubleMax - sumSoFar < valueToAddexponent > 709.783

value×2shift

#!/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)

Kahan toplamı, "telafi edilmiş toplam" metotlarının bir ailesidir. Bir nedenden dolayı Kahan tam olarak işe yaramazsa, değişen büyüklükler ve zıt işaretlerin terimlerini düzgün bir şekilde eklemek için bir dizi başka yöntem vardır.
JM

@JM bana bu diğer yöntemlerin isimlerini verebilir misiniz, bunları okumak için oldukça istekli olurum. Teşekkürler.
Gareth A. Lloyd


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.