Why does float64 produce a RuntimeWarning where float produces a nan?

泪湿孤枕 提交于 2020-01-17 05:39:06

问题


I'm using the warnings module to raise warnings as errors.

When I call my function plot_fig_4, I get the following error:

In [5]: plot_amit.plot_fig_4()
g: 1 of 3
theta_E: 1 of 1000
---------------------------------------------------------------------------
RuntimeWarning                            Traceback (most recent call last)
<ipython-input-5-5a631d2493d7> in <module>()
----> 1 plot_amit.plot_fig_4()

/home/dan/Science/dopa_net/plot_amit.pyc in plot_fig_4()
    130                                                                     tau_0, tau,
    131                                                                     theta_E_,
--> 132                                                                     H)
    133 
    134             # Iterate through theta_I, starting at the lowest value.

/home/dan/Science/dopa_net/plot_support.py in _get_d_phi(mu, sigma, tau_0, tau_i, theta_i, H)
   2059     for (i, mu_), (j, sigma_) in itertools.product(enumerate(mu),
   2060                                                    enumerate(sigma)):
-> 2061         phi[i, j] = _get_phi(tau_0, tau_i, theta_i, mu_, sigma_, H)
   2062     import pdb
   2063     pdb.set_trace()

/home/dan/Science/dopa_net/plot_support.py in _get_phi(tau_0, tau, theta_over_J, mu_over_J, sigma_over_J, H)
   1835 
   1836     # Compute the integral.
-> 1837     integral = _integrate_little_phi(lower, alpha)
   1838 
   1839     # Compute phi.

/home/dan/Science/dopa_net/plot_support.py in _integrate_little_phi(lower, upper)
   1869     upper_int = _integrate(upper)
   1870     lower_int = _integrate(lower)
-> 1871     return upper_int - lower_int
   1872 
   1873 

RuntimeWarning: invalid value encountered in double_scalars

OK. So I stick a pdb.set_trace inside _integrate_little_phi, just before the line at which the error is raised, re-run, and inspect the values of the relevant variables:

In [7]: plot_amit.plot_fig_4()
g: 1 of 3
theta_E: 1 of 1000
> /home/dan/Science/dopa_net/plot_support.py(1873)_integrate_little_phi()
-> return upper_int - lower_int
(Pdb) upper_int
inf
(Pdb) lower_int
inf
(Pdb) type(upper_int)
<type 'numpy.float64'>
(Pdb) type(lower_int)
<type 'numpy.float64'>

Huh. So the error was raised because I was subtracting infinity from infinity. Can I replicate that?

(Pdb) upper_int - lower_int
*** RuntimeWarning: invalid value encountered in double_scalars

Yes. But wait a minute. Let's try one more thing:

(Pdb) np.inf
inf
(Pdb) type(np.inf)
<type 'float'>
(Pdb) np.inf - np.inf
nan

What the what? When I directly subtract infinity from infinity using np.inf (where np is numpy), I get nan, not the RuntimeWarning.

Why do I get nan in this instance and RuntimeWarning in the other? I have posted the difference in type (float versus float64) deliberately. The question is, why do these (trivially) different types produce different results?


回答1:


Because in the case of np.inf , the type is float (the basic datatype) , whereas in case of upper_int / lower_int the data type is numpy.float64 . Similar issue can be reproduced by -

In [7]: a = np.float64('inf')

In [8]: type(a)
Out[8]: numpy.float64

In [9]: a - a
RuntimeWarning: invalid value encountered in double_scalars
  if __name__ == '__main__':
Out[9]: nan

For the case of np.inf / float -

In [3]: float('inf') - float('inf')
Out[3]: nan

In [11]: np.inf
Out[11]: inf

In [12]: type(np.inf)
Out[12]: float

I think this may be because in case of normal inf , you cannot get it from calculation. Example -

>>> 123123123123. ** 2
1.5159303447561418e+22
>>> _ ** 2
2.298044810152475e+44
>>> _ ** 2
5.281009949468725e+88
>>> _ ** 2
2.788906608638767e+177
>>> _ ** 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: (34, 'Result too large')

Instead you always get an overflow error.

Whereas when using np.float64 , you can get the infinity value from calculation (though even that time it would throw a warning) -

In [63]: n = np.float64('123123123123123123123')

In [64]: n
Out[64]: 1.2312312312312313e+20

In [65]: n = n ** 2

In [66]: n = n ** 2

In [67]: n = n ** 2

In [68]: n = n ** 2
C:\Anaconda3\Scripts\ipython-script.py:1: RuntimeWarning: overflow encountered in double_scalars
  if __name__ == '__main__':

In [69]: n
Out[69]: inf

Hence, since you can get np.float64 infinity through calculation, they are throwing more warnings, when you try to do more calculations on it that may try to reduce the number from infinity to a much smaller value , that is subtracting/dividing by infinity (multiplication or addition of infinity is fine, since adding infinity to infinity would only give back infinity). Example -

In [71]: n - n
C:\Anaconda3\Scripts\ipython-script.py:1: RuntimeWarning: invalid value encountered in double_scalars
  if __name__ == '__main__':
Out[71]: nan

In [72]: n/n
C:\Anaconda3\Scripts\ipython-script.py:1: RuntimeWarning: invalid value encountered in double_scalars
  if __name__ == '__main__':
Out[72]: nan

In [73]: n*n
Out[73]: inf

Though in your case , I believe you may have gotten a direct infinite value from source.




回答2:


There does not seem to be any reason a subtraction of two float64s should raise a warning where a subtraction of two floats doesn't.

Hence, this appears to be a bug in numpy.

My recommendation (to myself) is to convert the float64s to floats at the time of the subtraction: i.e.,

return upper_int - lower_int

becomes

return float(upper_int) - float(lower_int).

This prevents the warning.

(Of course, there may be situations in which a warning for this subtraction is desired -- for these, I'd give the opposite recommendation -- i.e., keep things as is. In a sense, it's nice to have this toggle for the warning.)



来源:https://stackoverflow.com/questions/32429925/why-does-float64-produce-a-runtimewarning-where-float-produces-a-nan

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!