How to make an integer larger than any other integer?

Question:

Note: while the accepted answer achieves the result I wanted, and @ecatmur answer provides a more comprehensive option, I feel it’s very important to emphasize that my use case is a bad idea in the first place. This is explained very well in @Jason Orendorff answer below.

Note: this question is not a duplicate of the question about sys.maxint. It has nothing to do with sys.maxint; even in python 2 where sys.maxint is available, it does NOT represent largest integer (see the accepted answer).

I need to create an integer that’s larger than any other integer, meaning an int object which returns True when compared to any other int object using >. Use case: library function expects an integer, and the only easy way to force a certain behavior is to pass a very large integer.

In python 2, I can use sys.maxint (edit: I was wrong). In python 3, math.inf is the closest equivalent, but I can’t convert it to int.

Asked By: max

||

Answers:

Since python integers are unbounded, you have to do this with a custom class:

import functools

@functools.total_ordering
class NeverSmaller(object):
    def __le__(self, other):
        return False

class ReallyMaxInt(NeverSmaller, int):
    def __repr__(self):
        return 'ReallyMaxInt()'

Here I’ve used a mix-in class NeverSmaller rather than direct decoration of ReallyMaxInt, because on Python 3 the action of functools.total_ordering would have been prevented by existing ordering methods inherited from int.

Usage demo:

>>> N = ReallyMaxInt()
>>> N > sys.maxsize
True
>>> isinstance(N, int)
True
>>> sorted([1, N, 0, 9999, sys.maxsize])
[0, 1, 9999, 9223372036854775807, ReallyMaxInt()]

Note that in python2, sys.maxint + 1 is bigger than sys.maxint, so you can’t rely on that.

Disclaimer: This is an integer in the OO sense, it is not an integer in the mathematical sense. Consequently, arithmetic operations inherited from the parent class int may not behave sensibly. If this causes any issues for your intended use case, then they can be disabled by implementing __add__ and friends to just error out.

Answered By: wim

It seems to me that this would be fundamentally impossible. Let’s say you write a function that returns this RBI (“really big int”). If the computer is capable of storing it, then someone else could write a function that returns the same value. Is your RBI greater than itself?

Perhaps you can achieve the desired result with something like @wim’s answer: Create an object that overrides the comparison operators to make “<” always return false and “>” always return true. (I haven’t written a lot of Python. In most object-oriented languages, this would only work if the comparison puts your value first, IF RBI>x. If someone writes the comparison the other way, IF x>RBI, it will fail because the compiler doesn’t know how to compare integers to a user-defined class.)

Answered By: Jay

Konsta Vesterinen’s infinity.Infinity would work (pypi), except that it doesn’t inherit from int, but you can subclass it:

from infinity import Infinity
class IntInfinity(Infinity, int):
    pass
assert isinstance(IntInfinity(), int)
assert IntInfinity() > 1e100

Another package that implements “infinity” values is Extremes, which was salvaged from the rejected PEP 326; again, you’d need to subclass from extremes.Max and int.

Answered By: ecatmur

Use case: library function expects an integer, and the only easy way to force a certain behavior is to pass a very large integer.

This sounds like a flaw in the library that should be fixed in its interface. Then all its users would benefit. What library is it?

Creating a magical int subclass with overridden comparison operators might work for you. It’s brittle, though; you never know what the library is going to do with that object. Suppose it converts it to a string. What should happen? And data is naturally used in different ways as a library evolves; you may update the library one day to find that your trick doesn’t work anymore.

Answered By: Jason Orendorff

Another way to do this (very much inspired by wim’s answer) might be an object that isn’t infinite, but increases on the fly as needed.

Here’s what I have in mind:

from functools import wraps

class AlwaysBiggerDesc():
    '''A data descriptor that always returns a value bigger than instance._compare'''
    def __get__(self, instance, owner):
        try:
            return instance._compare + 1
        except AttributeError:
            return instance._val
    def __set__(self, instance, value):
        try:
            del instance._compare
        except AttributeError:
            pass
        instance._val = value

class BiggerThanYou(int):
    '''A class that behaves like an integer but that increases as needed so as to be 
    bigger than "other" values. Defaults to 1 so that instances are considered
    to be "truthy" for boolean comparisons.'''
    val = AlwaysBiggerDesc()
    def __getattribute__(self, name):
        f = super().__getattribute__(name)
        try:
            intf = getattr(int,name)
        except AttributeError:
            intf = None
        if f is intf:
            @wraps(f)
            def wrapper(*args):
                try:
                    self._compare = args[1]
                except IndexError:
                    self._compare = 0 # Note: 1 will be returned by val descriptor
                new_bigger = BiggerThanYou()
                try:
                    new_bigger.val = f(self.val, *args[1:])
                except IndexError:
                    new_bigger.val =  f(self.val)
                return new_bigger
            return wrapper
        else:
            return f            
    def __repr__(self):
        return 'BiggerThanYou()'
    def __str__(self):
        return '1000...'

Something like this might avoid a lot of weird behavior that one might not expect. Note that with this kind of approach, if two BiggerThanYou instances are involved in an operation, the LHS would be considered bigger than the RHS.

EDIT: currently this is not working- I’ll fix it later. it seems I am being bitten by the special method lookup functionality.

In Python 3.5, you can do:

import math
test = math.inf

And then:

test > 1
test > 10000
test > x

Will always be true. Unless of course, as pointed out, x is also infinity or “nan” (“not a number”).

How can I represent an infinite number in Python?

Answered by @WilHall

Answered By: R__raki__

You should not be inheriting from int unless you want both its interface and its implementation. (Its implementation is an automatically-widening set of bits representing a finite number. You clearly dont’ want that.) Since you only want the interface, then inherit from the ABC Integral. Thanks to @ecatmur’s answer, we can use infinity to deal with the nitty-gritty of infinity (including negation). Here is how we could combine infinity with the ABC Integral:

import pytest
from infinity import Infinity
from numbers import Integral


class IntegerInfinity(Infinity, Integral):

    def __and__(self, other):
        raise NotImplementedError

    def __ceil__(self):
        raise NotImplementedError

    def __floor__(self):
        raise NotImplementedError

    def __int__(self):
        raise NotImplementedError

    def __invert__(self, other):
        raise NotImplementedError

    def __lshift__(self, other):
        raise NotImplementedError

    def __mod__(self, other):
        raise NotImplementedError

    def __or__(self, other):
        raise NotImplementedError

    def __rand__(self, other):
        raise NotImplementedError

    def __rlshift__(self, other):
        raise NotImplementedError

    def __rmod__(self, other):
        raise NotImplementedError

    def __ror__(self, other):
        raise NotImplementedError

    def __round__(self):
        raise NotImplementedError

    def __rrshift__(self, other):
        raise NotImplementedError

    def __rshift__(self, other):
        raise NotImplementedError

    def __rxor__(self, other):
        raise NotImplementedError

    def __trunc__(self):
        raise NotImplementedError

    def __xor__(self, other):
        raise NotImplementedError

def test():
    x = IntegerInfinity()
    assert x > 2
    assert not x < 3
    assert x >= 5
    assert not x <= -10
    assert x == x
    assert not x > x
    assert not x < x
    assert x >= x
    assert x <= x
    assert -x == -x
    assert -x <= -x
    assert -x <= x
    assert -x < x
    assert -x < -1000
    assert not -x < -x
    with pytest.raises(Exception):
        int(x)
    with pytest.raises(Exception):
        x | x
    with pytest.raises(Exception):
        ceil(x)

This can be run with pytest to verify the required invariants.

Answered By: Neil G
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.