Assigning a variable NaN in python without numpy

2019-01-16 17:55发布

问题:

Most languages have a NaN constant you can use to assign a variable the value NaN. Can python do this without using numpy?

回答1:

Yes -- use float('nan'). As of Python 3.5, you can also use math.nan.

>>> a = float('nan')
>>> print(a)
nan
>>> print(a + 2)
nan
>>> a == a
False
>>> import math
>>> math.isnan(a)
True
>>> # Python 3.5+
>>> math.isnan(math.nan)
True

The float(...) function is case-insensitive -- doing float('NAN') or float('naN') or similar things will also work.

Note that checking to see if two things that are NaN are equal to one another will always return false. This is in part because two things that are "not a number" cannot (strictly speaking) be said to be equal to one another -- see What is the rationale for all comparisons returning false for IEEE754 NaN values? for more details and information.

Instead, use math.isnan(...) if you need to determine if a value is NaN or not.

Furthermore, the exact semantics of the == operation on NaN value may cause subtle issues when trying to store NaN inside container types such as list or dict (or when using custom container types). See Checking for NaN presence in a container for more details.


You can also construct NaN numbers using Python's decimal module:

>>> from decimal import Decimal
>>> b = Decimal('nan')
>>> print(b)
NaN
>>> print(repr(b))
Decimal('NaN')
>>>
>>> Decimal(float('nan'))
Decimal('NaN')
>>> 
>>> import math
>>> math.isnan(b)
True

math.isnan(...) will also work with Decimal objects.


However, you cannot construct NaN numbers in Python's fractions module:

>>> from fractions import Fraction
>>> Fraction('nan')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python35\lib\fractions.py", line 146, in __new__
    numerator)
ValueError: Invalid literal for Fraction: 'nan'
>>>
>>> Fraction(float('nan'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python35\lib\fractions.py", line 130, in __new__
    value = Fraction.from_float(numerator)
  File "C:\Python35\lib\fractions.py", line 214, in from_float
    raise ValueError("Cannot convert %r to %s." % (f, cls.__name__))
ValueError: Cannot convert nan to Fraction.

Incidentally, you can also do float('Inf'), Decimal('Inf'), or math.inf (3.5+) to assign infinite numbers. (And also see math.isinf(...))

However doing Fraction('Inf') or Fraction(float('inf')) isn't permitted and will throw an exception, just like NaN.

If you want a quick and easy way to check if a number is neither NaN nor infinite, you can use math.isfinite(...) as of Python 3.2+.


If you want to do similar checks with complex numbers, the cmath module contains a similar set of functions and constants as the math module:

  • cmath.isnan(...)
  • cmath.isinf(...)
  • cmath.isfinite(...) (Python 3.2+)
  • cmath.nan (Python 3.6+; equivalent to complex(float('nan'), 0.0))
  • cmath.nanj (Python 3.6+; equivalent to complex(0.0, float('nan')))
  • cmath.inf (Python 3.6+; equivalent to complex(float('inf'), 0.0))
  • cmath.infj (Python 3.6+; equivalent to complex(0.0, float('inf')))


回答2:

nan = float('nan')

And now you have the constant, nan.

You can similarly create NaN values for decimal.Decimal.:

dnan = Decimal('nan')


回答3:

Use float("nan"):

>>> float("nan")
nan


回答4:

You can do float('nan') to get NaN.



回答5:

You can get NaN from "inf - inf", and you can get "inf" from a number greater than 2e308, so, I generally used:

>>> inf = 9e999
>>> inf
inf
>>> inf - inf
nan


回答6:

A more consistent (and less opaque) way to generate inf and -inf is to again use float():

>> positive_inf = float('inf')
>> positive_inf
inf
>> negative_inf = float('-inf')
>> negative_inf
-inf

Note that the size of a float varies depending on the architecture, so it probably best to avoid using magic numbers like 9e999, even if that is likely to work.

import sys
sys.float_info
sys.float_info(max=1.7976931348623157e+308,
               max_exp=1024, max_10_exp=308,
               min=2.2250738585072014e-308, min_exp=-1021,
               min_10_exp=-307, dig=15, mant_dig=53,
               epsilon=2.220446049250313e-16, radix=2, rounds=1)