Làm thế nào để thêm các thuật ngữ hàm mũ lớn đáng tin cậy mà không có lỗi tràn?


24

Một vấn đề rất phổ biến trong Markov Chain Monte Carlo liên quan đến xác suất tính toán là tổng của các thuật ngữ hàm mũ lớn,

ea1+ea2+...

trong đó các thành phần của có thể từ rất nhỏ đến rất lớn. Cách tiếp cận của tôi là đưa ra thuật ngữ hàm mũ lớn nhất để:aK:=maxi(ai)

e một 'e một 1 + e một 2 + . . .

a=K+log(ea1K+ea2K+...)
emột'emột1+emột2+...

Cách tiếp cận này là hợp lý nếu tất cả các yếu tố của một lớn, nhưng không phải là một ý tưởng tốt nếu chúng không. Tất nhiên, dù sao thì các phần tử nhỏ hơn không đóng góp vào tổng dấu phẩy động, nhưng tôi không chắc chắn làm thế nào để giải quyết chúng một cách đáng tin cậy. Trong mã R, cách tiếp cận của tôi trông giống như:

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

Có vẻ như một vấn đề đủ phổ biến là cần có một giải pháp chuẩn, nhưng tôi không chắc nó là gì. Cảm ơn cho bất kỳ đề nghị.


1
Đây là một điều. Google cho 'logumEx'.

Câu trả lời:


15

Có một giải pháp đơn giản chỉ với hai lần truyền dữ liệu:

Tính toán đầu tiên

K:=maxiai,

cho bạn biết rằng, nếu có điều khoản, thì Σ i e một in e K .n

ieaineK.

Vì có lẽ bạn không có ở bất cứ đâu gần bằng , nên bạn không phải lo lắng về việc tràn ra tính toán của với độ chính xác gấp đôi .n1020

τ:=ieaiKn

Do đó, tính toán và sau đó giải pháp của bạn là .τeKτ


Cảm ơn về ký hiệu rõ ràng - nhưng tôi tin rằng đây thực chất là những gì tôi đã đề xuất (?) Nếu tôi cần tránh các lỗi tràn khi một số nhỏ, tôi tập hợp tôi cần phương pháp tổng hợp Kahan do @gareth đề xuất ? mộttôi
cboettig

Ah, bây giờ tôi thấy những gì bạn đang nhận được. Bạn thực sự không cần phải lo lắng về dòng chảy, vì việc thêm các kết quả cực kỳ nhỏ vào giải pháp của bạn không nên thay đổi nó. Nếu có một số lượng lớn đặc biệt, thì bạn nên tổng hợp các giá trị nhỏ trước.
Jack Poulson

Đối với người downvoter: bạn có phiền khi cho tôi biết điều gì sai với câu trả lời của tôi không?
Jack Poulson

emộttôi-K0


10

Để giữ độ chính xác trong khi bạn cộng đôi, bạn cần sử dụng Kahan Summation , đây là phần mềm tương đương với việc có một thanh ghi mang theo.

e709.783doubleMax - sumSoFar < valueToAddexponent > 709.783

vmộttôibạne×2Shtôift

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

Tổng kết Kahan là một trong những phương pháp "tổng bù". Nếu vì một lý do nào đó Kahan không hoạt động hoàn toàn đúng, có một số phương pháp khác để thêm các thuật ngữ có cường độ khác nhau và các dấu hiệu ngược lại đúng cách.
JM

@JM bạn có thể cung cấp cho tôi tên của các phương thức khác đó không, tôi sẽ rất muốn đọc chúng. Cảm ơn.
Gareth A. Lloyd


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.