Pour conserver la précision pendant que vous ajoutez des doubles ensemble, vous devez utiliser Kahan Summation , c'est l'équivalent logiciel d'avoir un registre de retenue.
C'est très bien pour la plupart des valeurs, mais si vous obtenez un débordement, vous atteignez les limites de la double précision IEEE 754 qui serait d'environ . À ce stade, vous avez besoin d'une nouvelle représentation. Vous pouvez détecter un débordement au moment de l'ajout et également détecter des exposants trop grands pour être évalués par . À ce stade, vous pouvez modifier l'interprétation d'un double en décalant l'exposant et en gardant une trace de ce décalage.e709.783doubleMax - sumSoFar < valueToAdd
exponent > 709.783
Ceci est pour la plupart similaire à votre approche de décalage d'exposant, mais cette version est conservée en base 2 et ne nécessite pas de recherche initiale pour trouver le plus grand exposant. D'où .v a l u e × 2s h i f t
#!/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)