[ACCEPTED]-Python Infinity - Any caveats?-infinity

Accepted answer
Score: 105

Python's implementation follows the IEEE-754 standard pretty well, which you can 46 use as a guidance, but it relies on the 45 underlying system it was compiled on, so 44 platform differences may occur. Recently¹, a fix has been applied 43 that allows "infinity" as well as "inf", but that's of minor importance 42 here.

The following sections equally well 41 apply to any language that implements IEEE 40 floating point arithmetic correctly, it 39 is not specific to just Python.

Comparison for inequality

When dealing 38 with infinity and greater-than > or less-than 37 < operators, the following counts:

  • any number including +inf is higher than -inf
  • any number including -inf is lower than +inf
  • +inf is neither higher nor lower than +inf
  • -inf is neither higher nor lower than -inf
  • any comparison involving NaN is false (inf is neither higher, nor lower than NaN)

Comparison for equality

When compared 36 for equality, +inf and +inf are equal, as are -inf and 35 -inf. This is a much debated issue and may sound 34 controversial to you, but it's in the IEEE 33 standard and Python behaves just like that.

Of 32 course, +inf is unequal to -inf and everything, including 31 NaN itself, is unequal to NaN.

Calculations with infinity

Most calculations 30 with infinity will yield infinity, unless 29 both operands are infinity, when the operation 28 division or modulo, or with multiplication 27 with zero, there are some special rules 26 to keep in mind:

  • when multiplied by zero, for which the result is undefined, it yields NaN
  • when dividing any number (except infinity itself) by infinity, which yields 0.0 or -0.0².
  • when dividing (including modulo) positive or negative infinity by positive or negative infinity, the result is undefined, so NaN.
  • when subtracting, the results may be surprising, but follow common math sense:
    • when doing inf - inf, the result is undefined: NaN;
    • when doing inf - -inf, the result is inf;
    • when doing -inf - inf, the result is -inf;
    • when doing -inf - -inf, the result is undefined: NaN.
  • when adding, it can be similarly surprising too:
    • when doing inf + inf, the result is inf;
    • when doing inf + -inf, the result is undefined: NaN;
    • when doing -inf + inf, the result is undefined: NaN;
    • when doing -inf + -inf, the result is -inf.
  • using math.pow, pow or ** is tricky, as it doesn't behave as it should. It throws an overflow exception when the result with two real numbers is too high to fit a double precision float (it should return infinity), but when the input is inf or -inf, it behaves correctly and returns either inf or 0.0. When the second argument is NaN, it returns NaN, unless the first argument is 1.0. There are more issues, not all covered in the docs.
  • math.exp suffers the same issues 25 as math.pow. A solution to fix this for overflow 24 is to use code similar to this:

    try:
        res = math.exp(420000)
    except OverflowError:
        res = float('inf')
    

Notes

Note 1: as an additional 23 caveat, that as defined by the IEEE standard, if 22 your calculation result under-or overflows, the 21 result will not be an under- or overflow 20 error, but positive or negative infinity: 1e308 * 10.0 yields 19 inf.

Note 2: because any calculation with NaN returns 18 NaN and any comparison to NaN, including NaN itself 17 is false, you should use the math.isnan function to determine 16 if a number is indeed NaN.

Note 3: though Python supports 15 writing float('-NaN'), the sign is ignored, because there 14 exists no sign on NaN internally. If you divide 13 -inf / +inf, the result is NaN, not -NaN (there is no such 12 thing).

Note 4: be careful to rely on any of the 11 above, as Python relies on the C or Java 10 library it was compiled for and not all 9 underlying systems implement all this behavior 8 correctly. If you want to be sure, test 7 for infinity prior to doing your calculations.

¹) Recently 6 means since version 3.2.
²) Floating points support 5 positive and negative zero, so: x / float('inf') keeps its 4 sign and -1 / float('inf') yields -0.0, 1 / float(-inf) yields -0.0, 1 / float('inf') yields 0.0 and 3 -1/ float(-inf) yields 0.0. In addition, 0.0 == -0.0 is true, you have to manually 2 check the sign if you don't want it to be 1 true.

Score: 98

You can still get not-a-number (NaN) values 8 from simple arithmetic involving inf:

>>> 0 * float("inf")
nan

Note that 7 you will normally not get an inf value through 6 usual arithmetic calculations:

>>> 2.0**2
4.0
>>> _**2
16.0
>>> _**2
256.0
>>> _**2
65536.0
>>> _**2
4294967296.0
>>> _**2
1.8446744073709552e+19
>>> _**2
3.4028236692093846e+38
>>> _**2
1.157920892373162e+77
>>> _**2
1.3407807929942597e+154
>>> _**2
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
OverflowError: (34, 'Numerical result out of range')

The inf value 5 is considered a very special value with 4 unusual semantics, so it's better to know 3 about an OverflowError straight away through an exception, rather 2 than having an inf value silently injected 1 into your calculations.

Score: 3

So does C99.

The IEEE 754 floating point representation 8 used by all modern processors has several 7 special bit patterns reserved for positive 6 infinity (sign=0, exp=~0, frac=0), negative 5 infinity (sign=1, exp=~0, frac=0), and many 4 NaN (Not a Number: exp=~0, frac≠0).

All you 3 need to worry about: some arithmetic may 2 cause floating point exceptions/traps, but 1 those aren't limited to only these "interesting" constants.

Score: 3

I found a caveat that no one so far has 8 mentioned. I don't know if it will come 7 up often in practical situations, but here 6 it is for the sake of completeness.

Usually, calculating 5 a number modulo infinity returns itself 4 as a float, but a fraction modulo infinity 3 returns nan (not a number). Here is an example:

>>> from fractions import Fraction
>>> from math import inf
>>> 3 % inf
3.0
>>> 3.5 % inf
3.5
>>> Fraction('1/3') % inf
nan

I 2 filed an issue on the Python bug tracker. It 1 can be seen at https://bugs.python.org/issue32968.

Update: this will be fixed in Python 3.8.

Score: 3

A VERY BAD CAVEAT : Division by Zero

in a 1/x fraction, up to 2 x = 1e-323 it is inf but when x = 1e-324 or little it throws ZeroDivisionError

>>> 1/1e-323
inf

>>> 1/1e-324
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: float division by zero

so 1 be cautious!

More Related questions