Testing for positive infinity, or negative infinity, individually in Python
Asked Answered
F

3

50

math.isinf() tests for positive or negative infinity lumped together. What's the pythonic way to test for them distinctly?

Ways to test for positive infinity:

  1. x == float('+inf')
  2. math.isinf(x) and x > 0

Ways to test for negative infinity:

  1. x == float('-inf')
  2. math.isinf(x) and x < 0

Disassembly Way 1:

>>> def ispinf1(x): return x == float("inf")
...
>>> dis.dis(ispinf1)
  1           0 LOAD_FAST                0 (x)
              3 LOAD_GLOBAL              0 (float)
              6 LOAD_CONST               1 ('inf')
              9 CALL_FUNCTION            1
             12 COMPARE_OP               2 (==)
             15 RETURN_VALUE

Disassembly Way 2:

>>> def ispinf2(x): return isinf(x) and x > 0
...
>>> dis.dis(ispinfs)
  1           0 LOAD_GLOBAL              0 (isinf)
              3 LOAD_FAST                0 (x)
              6 CALL_FUNCTION            1
              9 JUMP_IF_FALSE_OR_POP    21
             12 LOAD_FAST                0 (x)
             15 LOAD_CONST               1 (0)
             18 COMPARE_OP               4 (>)
        >>   21 RETURN_VALUE

This answer seems to favor Way 2 except for the x>0.

Floorage answered 23/1, 2015 at 2:55 Comment(0)
S
57

The "pythonic" way is to go with what's readable and maintainable.

That said, x == float("inf") and x == float("-inf") are slightly more readable to me, and I'd prefer them. math.isinf(x) and x > 0 is faster, but only on the order of about 40 nanoseconds per call.

So unless you're checking a whole lot of numbers, it isn't going to make much of a difference in running time.

Stiletto answered 23/1, 2015 at 3:11 Comment(3)
If you are also using, e.g., sympy, math.isinf(sympy.oo) will give the correct answer while sympy.oo == float("inf") will be false.Inflection
It's also possible to store the result of float("inf") and float("-inf") in variables, to avoid the small penalty that is mentiod.Sigman
"only 40 on the order of about 40 nanoseconds per call"? ONLY??? that's a decade in cpu timeVermillion
G
22

there is also numpy

>>> import numpy as np
>>> np.isneginf([np.inf, 0, -np.inf])
array([False, False,  True], dtype=bool)
>>> np.isposinf([np.inf, 0, -np.inf])
array([ True, False, False], dtype=bool)

and then there is general isinf

>>> np.isinf([np.inf, 0, -np.inf])
array([ True, False,  True], dtype=bool)
Gibe answered 15/3, 2018 at 15:16 Comment(0)
G
0

Here are some jupyterlab timing tests, to see whats the fastest way (sorted from slowest to fastest):

Preparation:

import math
import numpy as np
n = 100000000
a = list(range(n))
a.extend([np.inf, float('inf'), math.inf])

Results:

%%time
def inf_to_none(x):
    if np.isinf(x):
        return None
    else:
        return x
r = list(map(inf_to_none, a))

>> CPU times: user 1min 30s, sys: 481 ms, total: 1min 31s
Wall time: 1min 31s


%%time
def inf_to_none(x):
    if x == float('inf'):
        return None
    else:
        return x
r = list(map(inf_to_none, a))

>> CPU times: user 19.6 s, sys: 494 ms, total: 20.1 s
Wall time: 20.2 s


%%time
def inf_to_none(x):
    if math.isinf(x):
        return None
    else:
        return x
r = list(map(inf_to_none_math, a))

>> CPU times: user 15 s, sys: 292 ms, total: 15.3 s
Wall time: 15.3 s


%%time
d = {np.inf: None}
l = lambda x: d.get(x,x)
r = list(map(l, a))

>> CPU times: user 11.7 s, sys: 256 ms, total: 12 s
Wall time: 12 s


%%time
def inf_to_none(x):
    if x == np.inf:
        return None
    else:
        return x
r = list(map(inf_to_none, a))

>> CPU times: user 11.2 s, sys: 280 ms, total: 11.5 s
Wall time: 11.5 s


%%time
def inf_to_none(x):
    if x == math.inf:
        return None
    else:
        return x
r = list(map(inf_to_none, a))

>> CPU times: user 11 s, sys: 276 ms, total: 11.3 s
Wall time: 11.3 s

I think those results are quite interesting, to make it short use == comparison.

Generation answered 17/12, 2021 at 8:24 Comment(1)
This would be interesting in the rare situation where speed is at stake. In that case globals would improve, e.g. from math import isinf and pinf = float('+inf')Floorage

© 2022 - 2024 — McMap. All rights reserved.