2010-06-08 21 views
4

Donc je viens de corriger un bug intéressant dans le code suivant, mais je ne suis pas sûr de l'approche que j'ai prise le meilleur:Comment faire face à des nombres flottants qui peuvent devenir si petits que le devenir

p = 1 
probabilities = [ ... ] # a (possibly) long list of numbers between 0 and 1 
for wp in probabilities: 

    if (wp > 0): 
    p *= wp 

# Take the natural log, this crashes when 'probabilites' is long enough that p ends up 
# being zero 
try: 
    result = math.log(p) 

Parce que le résultat n'a pas besoin d'être exact, je résolu ce problème en gardant simplement la plus petite valeur non nulle, et l'utilisation que si p est toujours 0.

p = 1 
probabilities = [ ... ] # a long list of numbers between 0 and 1 
for wp in probabilities: 

    if (wp > 0): 
    old_p = p 
    p *= wp 
    if p == 0: 
     # we've gotten so small, its just 0, so go back to the smallest 
     # non-zero we had 
     p = old_p 
     break 

# Take the natural log, this crashes when 'probabilites' is long enough that p ends up 
# being zero 
try: 
    result = math.log(p) 

cela fonctionne, mais il semble un peu kludgy à moi. Je ne fais pas une tonne de ce genre de programmation numérique, et je ne suis pas sûr si c'est le genre de correctif que les gens utilisent, ou s'il y a quelque chose de mieux que je peux faire.

Répondre

9

Depuis, math.log(a * b) est égal à math.log(a) + math.log(b), pourquoi ne pas prendre une somme des journaux de tous les membres du tableau probabilities?

Cela permettra d'éviter le problème de p si petit qu'il se décharge.

Edit: ceci est la version numpy, ce qui est plus propre et beaucoup plus rapide pour les grands ensembles de données:

import numpy 
prob = numpy.array([0.1, 0.213, 0.001, 0.98 ... ]) 
result = sum(numpy.log(prob)) 
+0

génie! Je savais que je devais retirer mon chapeau de programmeur et mettre mon chapeau de mathématicien pour celui-là :-) –