Never mind... the cases I mentioned are happy already:

>>> import numpy as np
>>> import torch
>>> import math
>>> math.isnan(np.nan), type(np.nan)
(True, <class 'float'>)
>>> np_nan = np.array(np.nan)
>>> math.isnan(np_nan), type(np_nan)
(True, <class 'numpy.ndarray'>)
>>> torch_nan = torch.Tensor([float('nan')])
>>> math.isnan(torch_nan), type(torch_nan)
(True, <class 'torch.Tensor'>)

Interestingly:

>>> np_nans = np.array([np.nan, np.nan])
>>> math.isnan(np_nans)
Traceback (most recent call last):
  File "<ipython-input-26-2f5da5ba4604>", line 1, in <module>
    math.isnan(np_nans)
TypeError: only size-1 arrays can be converted to Python scalars

>>> torch_nans = torch.Tensor([float('nan'), np.nan])
>>> torch_nans
tensor([nan, nan])
>>> math.isnan(torch_nans)
Traceback (most recent call last):
  File "<ipython-input-22-72715a2d3347>", line 1, in <module>
    math.isnan(torch_nans)
ValueError: only one element tensors can be converted to Python scalars

And yet:

>>> np_nan_arr = np.array([np.nan]).reshape(1, 1, 1, 1)
>>> math.isnan(np_nan_arr), np_nan_arr.shape
(True, (1, 1, 1, 1))

So it's really only the 1-element-ness being checked, not the 0-D shape.

On Fri, Dec 27, 2019 at 8:14 PM David Mertz <me...@gnosis.cx> wrote:

> Great work! I had not known if those corners.
>
> Have you tried with NumPy zero-D arrays or PyTorch Values? Both of those
> should have sensible answers.
>
> On Fri, Dec 27, 2019, 7:42 PM Steven D'Aprano <st...@pearwood.info> wrote:
>
>> By the way, it's not as easy as you might think to test whether a value
>> is a NAN or not.
>>
>> There are currently three ways to test whether a value is a NAN. (Four
>> if you include cmath.isnan.)
>>
>> 1. math.isnan(x) but it can fail in annoying ways.
>>
>>
>>     # No int is a NAN so this should return False
>>     py> math.isnan(10**1000)
>>     Traceback (most recent call last):
>>       File "<stdin>", line 1, in <module>
>>     OverflowError: int too large to convert to float
>>
>>     # Decimal signalling NANs are NANs so this should return True
>>     py> x = Decimal('snan')
>>     py> math.isnan(x)
>>     Traceback (most recent call last):
>>       File "<stdin>", line 1, in <module>
>>     ValueError: cannot convert signaling NaN to float
>>
>>
>> 2. Decimal.is_nan() but it only works with decimals. However it does
>> work with signalling NANs.
>>
>>
>> 3. Back before math.isnan existed, the idiomatic way to check for NANs
>> was to test whether they were equal to themselves. Assuming that x is a
>> kind of numeric type, we should expect that `x == x` except for NANs.
>> But this too fails for signalling NANs:
>>
>>
>>     # Using the default Decimal context
>>     py> x == x
>>     Traceback (most recent call last):
>>       File "<stdin>", line 1, in <module>
>>     decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]
>>
>>
>> So there is no good way to check for an arbitrary NAN that duck-types
>> floats, Decimals, ints, Fractions and other numeric types.
>>
>> I have come up with this:
>>
>>
>>     def isnan(x, _isnan=math.isnan):
>>         try:
>>             return _isnan(x)
>>         except ValueError:
>>             # Could be a Decimal signalling NAN.
>>             try:
>>                 return x.is_nan()
>>             except AttributeError:
>>                 return x != x
>>         except OverflowError:
>>             return False
>>         except TypeError:
>>             from cmath import isnan
>>             return isnan(x)
>>
>>
>> but I fear that there could be other landmines waiting, other odd corner
>> cases I haven't thought of.
>>
>> See also
>>
>> https://bugs.python.org/issue27975
>>
>>
>>
>> --
>> Steven
>> _______________________________________________
>> Python-ideas mailing list -- python-ideas@python.org
>> To unsubscribe send an email to python-ideas-le...@python.org
>> https://mail.python.org/mailman3/lists/python-ideas.python.org/
>> Message archived at
>> https://mail.python.org/archives/list/python-ideas@python.org/message/VHC4GO37ZT2UEW6RSRF4ASMTVK52UQ6H/
>> Code of Conduct: http://python.org/psf/codeofconduct/
>>
>

-- 
Keeping medicines from the bloodstreams of the sick; food
from the bellies of the hungry; books from the hands of the
uneducated; technology from the underdeveloped; and putting
advocates of freedom in prisons.  Intellectual property is
to the 21st century what the slave trade was to the 16th.
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/4KBOOPUES66FCHAYIKVORJB7IBRUEEDW/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to