ChocolateOverflow
ChocolateOverflow

Reputation: 480

Enabling Integer Overflow in Python

I'd like to create a 2D environment in which the top & bottom and left & right are connected (similar to a Torus or Doughnut). However, rather than doing a check on an object's x/y coordinate every frame, I'd like to simulate it using integer overflow.
While normal iteration (as shown in the sample code below) can be done, it may be slightly more effective (though dangerous) to simply enable overflow on some variables, especially when dealing with hundreds or thousands of objects in each frame/iteration.

I can find some examples which also simulate integer overflow in Python like this. However, I'm looking for something that can overflow just by enabling overflow in certain variables and skipping the checks in general.

# With normal checking of every instance
import random

width = 100
height = 100

class item():
    global width, height

    def __init__(self):
        self.x = random.randint(0, width)
        self.y = random.randint(0, height)

items = [item for _ in range(10)] # create 10 instances

while True:
    for obj in items:
        obj.x += 10
        obj.y += 20
        while obj.x > width:
            obj.x -= width
        while obj.y > height:
            obj.y -= height
        while obj.x < width:
            obj.x += width
        while obj.y < height:
            obj.y += height

I'd like to simulate integer overflow for only some certain classes/objects. Is there a way to have some variables automatically overflow and loop back to their min/max values?

Upvotes: 2

Views: 248

Answers (2)

wwii
wwii

Reputation: 23743

With a descriptor you can You can define the behavior you want for your object attributes. Reading between the lines it sounds like you want your attributes to exhibit a value = value % maximum behaviour.

from weakref import WeakKeyDictionary

class MaxValue:
    '''A descriptor whose value will be: value modulo maximum.'''
    def __init__(self, maximum, default=0):
        self.maximum = maximum
        self.default = default
        self.data = WeakKeyDictionary()

    def __get__(self, instance, owner):
        return self.data.get(instance, self.default)

    def __set__(self, instance, value):
        self.data[instance] = value % self.maximum

Descriptors should be class attributes. For your example class:

import random
width = 100
height = 100

class Item:
##    global width, height
    x = MaxValue(width)
    y = MaxValue(height)

    def __init__(self):
        self.x = random.randint(0, width)
        self.y = random.randint(0, height)
    def __str__(self):
        return f'({self.x:>3},{self.y:>3})'

Example:

items = [Item() for _ in range(5)]
print(','.join(f'{item}' for item in items))
for n in range(15):
    for item in items:
        item.x += 10
        item.y += 20
    print(','.join(f'{item}' for item in items))

>>>
( 74,  6),( 49, 19),( 56, 10),( 72, 16),( 83, 16)
( 84, 26),( 59, 39),( 66, 30),( 82, 36),( 93, 36)
( 94, 46),( 69, 59),( 76, 50),( 92, 56),(  3, 56)
(  4, 66),( 79, 79),( 86, 70),(  2, 76),( 13, 76)
( 14, 86),( 89, 99),( 96, 90),( 12, 96),( 23, 96)
( 24,  6),( 99, 19),(  6, 10),( 22, 16),( 33, 16)
( 34, 26),(  9, 39),( 16, 30),( 32, 36),( 43, 36)
( 44, 46),( 19, 59),( 26, 50),( 42, 56),( 53, 56)
( 54, 66),( 29, 79),( 36, 70),( 52, 76),( 63, 76)
( 64, 86),( 39, 99),( 46, 90),( 62, 96),( 73, 96)
( 74,  6),( 49, 19),( 56, 10),( 72, 16),( 83, 16)
( 84, 26),( 59, 39),( 66, 30),( 82, 36),( 93, 36)
( 94, 46),( 69, 59),( 76, 50),( 92, 56),(  3, 56)
(  4, 66),( 79, 79),( 86, 70),(  2, 76),( 13, 76)
( 14, 86),( 89, 99),( 96, 90),( 12, 96),( 23, 96)
( 24,  6),( 99, 19),(  6, 10),( 22, 16),( 33, 16)
>>>

Not my idea - picked this up at Python Descriptors Demystified


Each instance of MaxValue needs to keep track (or know) the value for each instance of Item - Item.x needs to know the x value for Item instances a, b, c,... . A dictionary is convenient for that and a WeakKeyDictionary is used so that if the dictionary is the only reference to an Item instance, then that instance can be garbage collected.

This solution alleviates the need to write a getter/setter for each attribute that shares a behaviour.

Upvotes: 1

wovano
wovano

Reputation: 5073

You can use properties to implement getters/setters with customized behaviour. For example like this:

import random

WIDTH = 100
HEIGHT = 100


class item():

    def __init__(self):
        self._x = random.randint(0, WIDTH - 1)
        self._y = random.randint(0, HEIGHT - 1)

    def __str__(self):
        return '(%r, %r)' % (self._x, self._y)

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, new_value):
        self._x = new_value % WIDTH

    @property
    def y(self):
        return self._y

    @y.setter
    def y(self, new_value):
        self._y = new_value % HEIGHT


items = [item() for _ in range(10)]

while True:
    for pos in items:
        pos.x += 10
        pos.y += 20
        print(pos)  # to show the results

Upvotes: 1

Related Questions