Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best approach to create an saturating integer in python?

Tags:

python-2.7

What would be the best approach to create a type that is a saturated integer in python ?

i.e.:

v = SaturatedInteger(0, 100) 
# That should create an integer that will always be in between 0 and 100,
# and have all default operations

v += 68719
print v #Should print '100'.

I can think of inheriting int type, but where should the saturating logic be implemented then ?

like image 274
Felipe Lavratti Avatar asked Apr 16 '26 06:04

Felipe Lavratti


2 Answers

If you need a new (quick and dirty) class for it, I would implement it as follows.

class SaturatedInteger:
    def __init__(self, val, lo, hi):
        self.real, self.lo, self.hi = val, lo, hi

    def __add__(self, other):
        return min(self.real + other.real, self.hi)

    def __sub__(self, other):
        return max(self.real - other.real, self.lo)

    ...

Add as many of the other operators in the docs as you feel you will need (and their 'r' variants).

By storing the value in the instance name real, you can do your arithmetic with regular integers, floats, etc. too:

a = SaturatedInteger(60, 0, 100)
print(a)
60
print(a+30)
90
print(a+40)
100
print(a+50.)
100
print(a-70.)
0
print(a+a)
100

Though, of course you only add the real part if you're adding a complex number to your SaturatedInteger, so watch out. (For a much more complete and robust version, @jonrsharpe's answer is the way to go).

like image 190
xnx Avatar answered Apr 19 '26 02:04

xnx


In general, I would implement using a @property to protect an instance's value attribute, then emulate a numeric type, rather than inheriting from int:

class SaturatedInteger(object):
    """Emulates an integer, but with a built-in minimum and maximum."""

    def __init__(self, min_, max_, value=None):
        self.min = min_
        self.max = max_
        self.value = min_ if value is None else value

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, new_val):
        self._value = min(self.max, max(self.min, new_val))

    @staticmethod
    def _other_val(other):
        """Get the value from the other object."""
        if hasattr(other, 'value'):
            return other.value
        return other

    def __add__(self, other):
        new_val = self.value + self._other_val(other)
        return SaturatedInteger(self.min, self.max, new_val)

    __radd__ = __add__

    def __eq__(self, other):
        return self.value == self._other_val(other)


if __name__ == '__main__':
    v = SaturatedInteger(0, 100)
    v += 68719
    assert v == 100
    assert 123 + v == 100

I've only implemented __add__, __radd__ and __eq__, but you can probably see how the rest could be built out as required. You might want to think about what happens when two SaturatedIntegers are used together - should the result have e.g. min(self.min, other.min) as its own min?

like image 25
jonrsharpe Avatar answered Apr 19 '26 02:04

jonrsharpe