【问题标题】:Enabling Integer Overflow in Python在 Python 中启用整数溢出
【发布时间】:2019-05-26 14:24:01
【问题描述】:

我想创建一个上下和左右相连的 2D 环境(类似于 Torus 或 Doughnut)。但是,我不想每帧检查对象的 x/y 坐标,而是使用整数溢出来模拟它。
虽然可以进行正常迭代(如下面的示例代码所示),但在某些变量上简单地启用溢出可能会更有效(尽管很危险),尤其是在每帧/迭代中处理数百或数千个对象时。

我可以找到一些在 Python 中也可以模拟整数溢出的示例,例如 this。但是,我正在寻找可以通过在某些变量中启用溢出并跳过一般检查来溢出的东西。

# 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

我只想为某些特定的类/对象模拟整数溢出。有没有办法让一些变量自动溢出并循环回到它们的最小值/最大值?

【问题讨论】:

  • Python 整数不会溢出。如果他们这样做了,它们不会在 100 或您选择的任何其他值处溢出,它们会根据计算机的位大小以 2 的幂次方溢出。例如,您只需要obj.x = (obj.x + 10) % width
  • 如果最大值为100,当item.x99item.x += 10会产生item.x --&gt; 9item.x --&gt; 0
  • jasonharper 的 obj.x = (obj.x + 10) % width 非常像我正在寻找的东西,其中 99 + 10 等于 9。我希望能够启用溢出,即使它仅适用于 2^x 整数.

标签: python integer-overflow


【解决方案1】:

您可以使用properties 来实现具有自定义行为的getter/setter。比如这样:

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

【讨论】:

【解决方案2】:

您可以使用描述符定义对象属性所需的行为。从字里行间看,听起来您希望您的属性表现出value = value % maximum 行为。

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

描述符应该是类属性。对于您的示例类:

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})'

例子:

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)
>>>

不是我的想法 - 在 Python Descriptors Demystified 上找到的


MaxValue 的每个实例都需要跟踪(或知道Item 的每个实例的值 - Item.x 需要知道 x Item 实例 abc、...的值。字典很方便,并且使用了 WeakKeyDictionary,这样如果字典是对 Item 实例的唯一引用,那么该实例可以被垃圾回收。

此解决方案减少了为共享行为的每个属性编写 getter/setter 的需要。

【讨论】:

  • 有趣的答案!我对描述符知之甚少,但总的来说,这似乎是一个不错的解决方案。虽然我认为弱引用的使用使解决方案比必要的复杂一些。只是感觉不适合我。你知道有什么其他方法可以避免这种情况吗?
  • @wovano,我环顾四周,另一个选择是将值存储在 Item 实例中,描述符的 __init__ 需要一个 field 参数(@987654338 @); __get__(self, instance, owner) 看起来像 return instance.__dict__.get(self.field, self.default);和__set__(self, instance, value) 看起来像instance.__dict__[self.field] = value % self.maximum
  • Example on github 存储在 instances 上。
  • 感谢您的搜索和其他 cmets。稍后我会仔细研究它们!描述符似乎有可能提供更好的解决方案,但我到目前为止看到的解决方案仍然感觉有点笨拙,恕我直言。我仍在寻找最佳解决方案:-)
猜你喜欢
  • 1970-01-01
  • 2022-01-21
  • 1970-01-01
  • 2014-01-24
  • 1970-01-01
  • 1970-01-01
  • 2021-02-27
  • 1970-01-01
相关资源
最近更新 更多