Имитация целочисленного переполнения в Python - PullRequest
7 голосов
/ 14 октября 2011

Python 2 имеет два целочисленных типа данных int и long и автоматически конвертирует между ними при необходимости, особенно во избежание целочисленного переполнения.

Я имитирую функцию C в Python и мне интересно, есть ли стандартные способы повторно включить целочисленное переполнение. Для одноразового использования я использовал

overflow_point = maxint + 1
if value > overflow_point:
    value -= 2 * overflow_point

Есть ли более стандартный способ сделать то же самое?

Ответы [ 4 ]

9 голосов
/ 14 октября 2011

Я думаю, что основная идея - это звук, но нужны некоторые настройки:

  1. ваша функция не переполняется на sys.maxint+1, но должна;
  2. sys.maxint может быть превышено в несколько раз в результате одной операции;
  3. отрицательные значения ниже -sys.maxint-1 также необходимо учитывать.

Имея это в виду, я придумал следующее:

import sys

def int_overflow(val):
  if not -sys.maxint-1 <= val <= sys.maxint:
    val = (val + (sys.maxint + 1)) % (2 * (sys.maxint + 1)) - sys.maxint - 1
  return val
7 голосов
/ 10 января 2013

Эта функция должна преобразовывать ваши числа в аппаратные целые числа.В зависимости от вашего приложения вам может потребоваться применить эту функцию на каждом этапе ваших операций.

def correct(value, bits, signed):
    base = 1 << bits
    value %= base
    return value - base if signed and value.bit_length() == bits else value

Следующие функции быстрого вызова могут пригодиться для «приведения» значений в соответствующий диапазон:

byte, sbyte, word, sword, dword, sdword, qword, sqword = (
    lambda v: correct(v, 8, False), lambda v: correct(v, 8, True),
    lambda v: correct(v, 16, False), lambda v: correct(v, 16, True),
    lambda v: correct(v, 32, False), lambda v: correct(v, 32, True),
    lambda v: correct(v, 64, False), lambda v: correct(v, 64, True)
)

В качестве примера того, как вы могли бы их использовать, может быть воспроизведена ошибка, которую можно увидеть в C. Если написать цикл for, используя байт для вывода 0 - 255, цикл может никогда не закончиться.Следующая программа демонстрирует эту проблему:

#! /usr/bin/env python3
def main():
    counter = 0
    while counter < 256:
        print(counter)
        counter = byte(counter + 1)


def correct(value, bits, signed):
    base = 1 << bits
    value %= base
    return value - base if signed and value.bit_length() == bits else value


byte, sbyte, word, sword, dword, sdword, qword, sqword = (
    lambda v: correct(v, 8, False), lambda v: correct(v, 8, True),
    lambda v: correct(v, 16, False), lambda v: correct(v, 16, True),
    lambda v: correct(v, 32, False), lambda v: correct(v, 32, True),
    lambda v: correct(v, 64, False), lambda v: correct(v, 64, True)
)


if __name__ == '__main__':
    main()
4 голосов
/ 14 октября 2011

Использует ли ваша функция деление или сдвиг вправо? Если нет, то вы не нужно беспокоиться о переполнениях на каждом этапе расчета, потому что вы всегда получите «правильный» ответ по модулю 2 ^ 32 или 2 ^ 64. До возврат результата (или перед делением или правильным сдвигом битов) Вы можете нормализовать обратно к стандартному целочисленному диапазону, используя что-то как

import sys

HALF_N = sys.maxint + 1
N = HALF_N * 2

def normalize(value):
    return (value + HALF_N) % N - HALF_N
3 голосов
/ 14 октября 2011

Я не знаю, что есть удобный способ сделать это изначально, потому что это обычно не считается проблемой, так что это не то, что разработчики Python хотели бы встроить. Я думаю, что вы делаете это хорошо.Вы можете даже создать подкласс встроенного типа int и переопределить методы операторов __add__(), __sub__() и т. Д., Чтобы включить ваши функциональные возможности, но это может быть излишним.

...