102

Python 3 has float('inf') and Decimal('Infinity') but no int('inf'). So, why a number representing the infinite set of integers is missing in the language? Is int('inf') unreasonable?

Elias Zamaria
  • 96,623
  • 33
  • 114
  • 148
Carlo Pires
  • 4,606
  • 7
  • 32
  • 32
  • 16
    There is no standard that defines integer infinity. The [Floating Point standard](http://en.wikipedia.org/wiki/IEEE_754-1985) however, does. Since `anyinteger < float('inf')` is true, we don't exactly *need* another infinity value. – Martijn Pieters Jul 05 '14 at 15:44
  • 9
    Infinity is not an integer. It's not a real number either but it comes up more often in the kind of arithmetic that floating point numbers are used for (e.g. involving transcendental and trigonometric functions). In addition, it's good for representing *finite, but too large to represent* which can't happen with Python 3 `int`. –  Jul 05 '14 at 15:53
  • 2
    @MartijnPieters, while `anyint < float('inf')` is ok, `int(float('inf'))` raises an exception. This lead us to deal with this special number in float/decimal -> integer conversions. – Carlo Pires Jul 05 '14 at 16:15
  • 2
    @CarloPires: And that is entirely logical, because *it is not a number*. Instead, a `OverflowError: cannot convert float infinity to integer` is raised. – Martijn Pieters Jul 05 '14 at 16:16
  • 1
    For IEEE floats, [inf is a defined bit pattern](http://www.astro.umass.edu/~weinberg/a732/notes07_01.pdf) There is not such defined pattern for any int. You could define one for your own use I suppose. – dawg Jul 05 '14 at 18:31
  • 5
    @MartijnPieters The floating point standard has nothing to do with this question. – Neil G Mar 01 '16 at 13:30
  • 1
    @NeilG: of course it does. The OP cites the existence of `float('inf')`. That is defined by a standard. There is no such definition for a `int('inf')`. – Martijn Pieters Mar 01 '16 at 13:38
  • @MartijnPieters Only because Python doesn't have one. It is possible to have a sentinel class for integer infinities. – Neil G Mar 01 '16 at 14:03
  • @NeilG: so what language *does*? – Martijn Pieters Mar 01 '16 at 14:05
  • 1
    @MartijnPieters None that I know of. However, I think it would still be a good idea if maybe a bit too much work to justify it. – Neil G Mar 01 '16 at 14:06
  • 1
    @NeilG: Sounds like a bad idea then; see the [*Zen of Python*](https://www.python.org/dev/peps/pep-0020/): *If the implementation is hard to explain, it's a bad idea.*; the same applies to ideas; if they are hard to justify, then why introduce the extra complexity at all? – Martijn Pieters Mar 01 '16 at 14:08
  • @MartijnPieters Yeah on second thought, most use cases are supplanted by `math.inf`. I think that's a better answer to this question. – Neil G Mar 01 '16 at 14:09
  • I added an implementation of `int_inf` to my answer. – Neil G Jun 25 '19 at 19:53
  • 1
    One use case for int('inf') would be in for range loops, `for i in range(int('inf'))` which would iterate endlessly. This is now done by while loop, but that looks ugly since you have to increment manually. And what if I mess with my `i` inside the loop, then I'd have to copy it to `i_` or something like that – Superior Jul 22 '20 at 08:08
  • 2
    Since `int` is unbounded in Python 3 `int('inf')` would definitely help with typing, especially when Mypy is used. For example: https://stackoverflow.com/q/54784280/4755520. – ayorgo Mar 16 '21 at 19:02
  • 1
    an infinite integer would be very useful. For cases where you're calculating some minimum it is a great default value, and if you use float as the default value you have to again check after iteration whether the value is still float('inf') some how – ICW May 28 '22 at 03:05

3 Answers3

20

You are right that an integer infinity is possible, and that none has been added to the Python standard. This is probably because math.inf supplants it in almost all cases (as Martijn stated in his comment).

In the meantime, I added an implementation of extended integers on PyPI:

In [0]: from numbers import Integral, Real

In [0]: from extended_int import int_inf, ExtendedIntegral, Infinite

In [0]: i = int_inf

In [4]: float(i)
Out[4]: inf

In [5]: print(i)
inf

In [6]: i ** i

Out[6]: inf

In [7]: i
Out[7]: inf

In [9]: isinstance(i, Real)

Out[9]: True

In [10]: isinstance(i, Integral)

Out[10]: False

In [11]: isinstance(i, Infinite)

Out[11]: True

In [12]: isinstance(i, ExtendedIntegral)

Out[12]: True

In [13]: isinstance(2, ExtendedIntegral)

Out[13]: True

In [14]: isinstance(2, Infinite)

Out[14]: False
Neil G
  • 32,138
  • 39
  • 156
  • 257
  • I don't get it. Why is your integer inf a Real and not an Integral? Shouldn't it be exactly the other way around? For me, one use case for an inf integer is to avoid warnings in case a function expects an integer but math.inf would pass as float. – Cerno Dec 12 '21 at 10:17
  • @Cerno there is no way to make an infinite integer that satisfies an integer type annotation. And all integers (including infinite ones) are instances of `Real`. Your use case would be satisfied by annotating using `ExtendedIntegral`. – Neil G Dec 12 '21 at 10:19
  • I understand the limitations you are operating under. However, if I had to choose between using math.inf (which is straightforward about being a Real number) and an implementation where a seemingly Integral number does not pass the Integral check, I would probably choose the former. The optimal solution, a proper integer inf, does not seem to be achievable, which is unfortunate – Cerno Dec 12 '21 at 10:26
  • @Cerno I don't know what you mean by "straightforward". You could use infinite integral when you control the interface, you want type annotations to work, and you want strict type annotations. Your idea would force a loose annotation. – Neil G Dec 12 '21 at 10:28
  • Sorry, maybe I picked the wrong word. What I meant is that math.inf is open about being a float and not an int, so the user would expect `isinstance(math.inf, numbers.Real)` to be True and `isinstance(math.inf, numbers.Integral)` to be False. However, if I have an instance of `ExtendedIntegral` it is natural to expect `isinstance(math.inf, numbers.Integral)` to be True and `isinstance(math.inf, numbers.Real)` to False, not the other way around. Maybe I am missing something, but what is the benefit of using `int_inf` over `math.inf`? – Cerno Dec 12 '21 at 10:44
  • There are a number of errors in your comments: Even with integers the user expects `isinstance(x, numbers.Real)` to be true, so this point of your is irrelevant to the discussion. It is not not "natural" to ever assume that an infinite integer can satisfy the `Integral` interface. It is completely incorrect for an instance of `ExtendedIntegral` not to satisfy `numbers.Real`—have you tested `isinstance(1, numbers.Real)`? Perhaps you should read the interfaces since you don't seem to understand their definition. – Neil G Dec 12 '21 at 10:54
  • You are right, I was misled by the fact that in C++ we are using helper functions that distinguish between integral and floating types. In these cases a `float` is not integral and an `int` is not a floating point number. I did not know that in python an integer is both `Real` and `Integral`. Thanks for clearing that up. I still need clarification on the other issue though: Why would an `ExtendedIntegral` not be `Integral`? I understand how an `Integral` can also be a `Real`, but shouldn't an extension of something still be that something? – Cerno Dec 12 '21 at 11:39
  • @Carno ExtendedIntegral cannot be Integral since it contains elements that are not Integral. – Neil G Dec 12 '21 at 14:25
  • @cerno Have you seen the [Numeric Tower](https://docs.python.org/3/library/numbers.html)? – Neil G Dec 12 '21 at 20:13
  • 1
    Yes, I think I understood the numeric tower, insofar as an int is also a rational which is also a real, which is also a complex number which is a number. Looking at your source code it seems like you inserted the ExtendedInteger between the Integral and the Real. So if I get this right, your ExtendedInteger is not an Integer subclass, but more of a superclass? – Cerno Dec 12 '21 at 22:42
  • So in your hierarchy a regular Integral is also an ExtendedIntegral, but not vice-versa, right? My confusion apparently came from the naming you chose, because my intuition would be that an extension to a thing is that thing and more. Could you give me a little more insight as to what elements ExtendedIntegral has that do not make it Integral? Isn't the whole point of the type to give the Integral type its own infinity? Wouldn't that just be an Integral with something on top? And if so, shouldn't it be below the Integral in the hierarchy? It seems there's still something I don't understand. – Cerno Dec 12 '21 at 22:49
  • @cerno Yes, you got it! The name is analogous to the *extended reals*. The extended integers are the integers plus two elements: positive and negative infinity. You asked: "shouldn't it be below the Integral"--no, it has to be above. Think about what "is a" means in inheritance. – Neil G Dec 12 '21 at 22:53
  • 1
    Ah, so mathematically speaking, we are adding stuff as we go _up_ the hierarchy. So from int to rational we add nominator and denominator, to real we add floating point numbers, to complex we add the imaginary component. I think I was confused, because the way the numeric tower is written, my first take was that it adds functionality as it goes down the hierarchy, but that is just specific functions that are relevant for the current level, or defaults for the extra stuff introduced in the higher levels. It's a bit weird the way it's set up but I think I get it now. Thanks for your patience. – Cerno Dec 12 '21 at 23:46
  • Can't use this to make an object with a boundless `__len__` because Real is not derived from int. – Gareth Davidson Jun 17 '23 at 00:06
  • @GarethDavidson You can return anything from `__len__` that you want. However, if you don't return an `int`, then your object cannot be a `collections.abc.Container`. Unbounded containers are not valid `Container`s. – Neil G Jun 18 '23 at 01:29
13

Taken from here: https://www.gnu.org/software/libc/manual/html_node/Infinity-and-NaN.html

IEEE 754 floating point numbers can represent positive or negative infinity, and NaN (not a number)

That is, the representation of float and Decimal can store these special values. However, there is nothing within the basic type int that can store the same. As you exceed the limit of 2^32 in an unsigned 32-bit int, you simply roll over to 0 again.

If you want, you could create a class containing an integer which could feature the possibility of infinite values.

  • 36
    2**10000 is fine in Python 3. Integer implementation has no limits anymore, but int('inf') special type is missing. – Carlo Pires Jul 05 '14 at 16:07
5

For python 2. It is sometimes the case that you need a very large integer. For example, I may want to produce a subarray with x[:n] and, I may wish to sometimes set n to a value such that the whole array will be produced. Since you can't use a float for n (python wants an integer), you need a "large integer". A good way of doing this is to use the largest integer available: sys.maxint. Here is an example:

# MAX_SOURCES = sys.maxint # normal setting
MAX_SOURCES = 5 # while testing

# code to use an array ...
... sources[:MAX_SOURCES]

So, while testing, I could use a smaller sources array but use the full array in production.

  • 11
    You can use `None` for this. Setting one of the endpoints of a slice to `None` is equivalent to omitting it. – Kevin Mar 05 '15 at 14:31
  • Kind of dirty IMHO,in addition to this, sys.maxint has been removed in Python3. Like @Kevin said, [use None](http://stackoverflow.com/questions/6723009/python-integer-infinity-for-slicing/6723022#6723022) – Pedru Dec 08 '15 at 09:00
  • 1
    Doesn't answer the question. – Neil G Mar 01 '16 at 13:29