在Python中模拟整数溢出

10 投票
5 回答
9794 浏览
提问于 2025-04-17 04:20

在Python 2中,有两种整数类型,分别是intlong,它们会根据需要自动转换,以避免整数溢出的问题。

我正在用Python模拟一个C语言的函数,想知道有没有标准的方法可以重新启用整数溢出。现在我用的是

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

有没有更标准的方法来做到这一点呢?

5 个回答

5

你的函数有没有用到除法或者右移位运算?如果没有的话,你就不需要担心在计算的每个阶段会出现溢出,因为你总是能得到“正确”的结果,结果会在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
8

这个函数的作用是把你的数字转换成看起来像硬件整数的样子。根据你的应用需求,你可能需要在每一步操作之间都使用这个函数。

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语言中遇到一个bug。如果你用一个字节来写一个循环,打印出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()
13

我觉得这个基本想法是不错的,但需要一些调整:

  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

撰写回答