¿Cómo agregar grandes términos exponenciales de manera confiable sin errores de desbordamiento?


24

Un problema muy común en Markov Chain Monte Carlo implica calcular probabilidades que son la suma de términos exponenciales grandes,

ea1+ea2+...

donde los componentes de lata pueden variar de muy pequeños a muy grandes. Mi enfoque ha sido factorizar el término exponencial más grande para que:aK:=maxi(ai)

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

Este enfoque es razonable si todos los elementos de a son grandes, pero no es una buena idea si no lo son. Por supuesto, los elementos más pequeños no contribuyen a la suma de punto flotante de todos modos, pero no estoy seguro de cómo tratarlos de manera confiable. En el código R, mi enfoque se ve así:

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

Parece un problema bastante común que debería haber una solución estándar, pero no estoy seguro de cuál es. Gracias por cualquier sugerencia


1
Esto es una cosa Google para 'logsumexp'.

Respuestas:


15

Hay una solución sencilla con solo dos pasos a través de los datos:

Primer cálculo

K:=maxiai,

que le dice que, si hay términos, entonces n

ieaineK.

Como presumiblemente no tiene cerca de , no debe preocuparse por desbordarse en el cálculo de con doble precisión .n1020

τ:=ieaiKn

Por lo tanto, calcule y luego su solución es e K τ .τeKτ


Gracias por la notación clara - pero creo que esto es esencialmente lo que he propuesto Si necesito para evitar errores de subdesbordamiento cuando algunos (?) son pequeños, tengo entendido que necesito el enfoque propuesto por la suma Kahan @gareth ? unayo
cboettig

Ah, ahora veo a qué te referías. En realidad, no necesita preocuparse por el flujo insuficiente, ya que agregar resultados excepcionalmente pequeños a su solución no debería cambiarlo. Si hubo un número excepcionalmente grande de ellos, entonces debe sumar los valores pequeños primero.
Jack Poulson

Para el votante: ¿le importaría decirme qué hay de malo en mi respuesta?
Jack Poulson

¿Qué pasa si tienes muchos términos muy pequeños? Podría suceder que para estos. Si hay muchos términos como este, tendría un gran error. miunayo-K0 0
Becko


10

Para mantener la precisión mientras agrega dobles, debe usar Kahan Summation , este es el software equivalente a tener un registro de acarreo.

Esto está bien para la mayoría de los valores, pero si obtiene un desbordamiento, entonces está alcanzando los límites de la precisión doble IEEE 754, que sería aproximadamente . En este punto necesitas una nueva representación. Puede detectar un desbordamiento en el momento de la adición y también detectar exponentes demasiado grandes para evaluarlos . En este punto, puede modificar la interpretación de un doble cambiando el exponente y haciendo un seguimiento de este cambio.mi709.783doubleMax - sumSoFar < valueToAddexponent > 709.783

En su mayor parte, esto es similar a su enfoque de compensación de exponente, pero esta versión se mantiene en la base 2 y no requiere una búsqueda inicial para encontrar el exponente más grande. Por lo tanto, .vunaltumi×2shyoFt

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

La suma de Kahan no es más que una de una familia de métodos de "suma compensada". Si por alguna razón Kahan no funciona del todo bien, hay varios otros métodos para sumar términos de diferentes magnitudes y signos opuestos correctamente.
JM

@JM, ¿podría proporcionarme los nombres de esos otros métodos? Me interesaría mucho leerlos. Gracias.
Gareth A. Lloyd


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.