Ik heb het volgende script geschreven:
import numpy
d = numpy.array([[1089, 1093]])
e = numpy.array([[1000, 4443]])
answer = numpy.exp(-3 * d)
answer1 = numpy.exp(-3 * e)
res = answer.sum()/answer1.sum()
print res
Maar ik kreeg dit resultaat en de fout trad op:
nan
C:\Users\Desktop\test.py:16: RuntimeWarning: invalid value encountered in double_scalars
res = answer.sum()/answer1.sum()
Het lijkt erop dat het invoerelement te klein was dat Python ze in nullen veranderde, maar de deling heeft inderdaad zijn resultaat.
Hoe dit soort problemen op te lossen?
Antwoord 1, autoriteit 100%
Je kunt het niet oplossen. Gewoon answer1.sum()==0
, en je kunt niet delen door nul.
Dit gebeurt omdat answer1
de exponentiële waarde is van 2 zeer grote, negatieve getallen, zodat het resultaat naar nul wordt afgerond.
nan
wordt in dit geval geretourneerd vanwege de deling door nul.
Om uw probleem nu op te lossen, kunt u:
- ga naar een bibliotheek voor zeer nauwkeurige wiskunde, zoals mpmath. Maar dat is minder leuk.
- Voer als alternatief voor een groter wapen wat wiskundige bewerkingen uit, zoals hieronder beschreven.
- ga voor een op maat gemaakte
scipy/numpy
-functie die precies doet wat je wilt! Bekijk het antwoord van @Warren Weckesser.
Hier leg ik uit hoe je wat wiskundige manipulatie kunt doen die bij dit probleem helpt. We hebben dat voor de teller:
exp(-x)+exp(-y) = exp(log(exp(-x)+exp(-y)))
= exp(log(exp(-x)*[1+exp(-y+x)]))
= exp(log(exp(-x) + log(1+exp(-y+x)))
= exp(-x + log(1+exp(-y+x)))
Waar bovendien x=3* 1089
en y=3* 1093
. Nu is het argument van deze exponentiële
-x + log(1+exp(-y+x)) = -x + 6.1441934777474324e-06
Voor de noemer zou je op dezelfde manier kunnen doorgaan, maar verkrijg je dat log(1+exp(-z+k))
is al afgerond op 0
, zodat het argument van De exponentiële functie bij de noemer wordt eenvoudig afgerond op -z=-3000
. U hebt dan dat uw resultaat
is
exp(-x + log(1+exp(-y+x)))/exp(-z) = exp(-x+z+log(1+exp(-y+x))
= exp(-266.99999385580668)
die al uitermate dicht bij het resultaat is dat u zou krijgen als u alleen de 2 leidende termen zou houden (dwz het eerste nummer 1089
in de teller en het eerste nummer 1000
bij de noemer):
exp(3*(1089-1000))=exp(-267)
Laten we eens kijken hoe dicht we komen uit de oplossing van Wolfram Alpha (Link ):
Log[(exp[-3*1089]+exp[-3*1093])/([exp[-3*1000]+exp[-3*4443])] -> -266.999993855806522267194565420933791813296828742310997510523
Het verschil tussen dit nummer en de bovenstaande exponent is +1.7053025658242404e-13
, dus de benadering die we bij de noemer maakten, was prima.
Het eindresultaat is
'exp(-266.99999385580668) = 1.1050349147204485e-116
Vanaf Wolfram Alpha is (Link )
1.105034914720621496.. × 10^-116 # Wolfram alpha.
En nogmaals, het is veilig om hier ook Numpy te gebruiken.
Antwoord 2, Autoriteit 23%
U kunt np.logaddexp
(die het idee implementeert in het antwoord van @ GG349):
In [33]: d = np.array([[1089, 1093]])
In [34]: e = np.array([[1000, 4443]])
In [35]: log_res = np.logaddexp(-3*d[0,0], -3*d[0,1]) - np.logaddexp(-3*e[0,0], -3*e[0,1])
In [36]: log_res
Out[36]: -266.99999385580668
In [37]: res = exp(log_res)
In [38]: res
Out[38]: 1.1050349147204485e-116
Of u kunt scipy.special.logsumexp
:
In [52]: from scipy.special import logsumexp
In [53]: res = np.exp(logsumexp(-3*d) - logsumexp(-3*e))
In [54]: res
Out[54]: 1.1050349147204485e-116