Simulating integer overflow in Python
Does your function use division or right bit-shifting? If not then you don't need to worry about overflows at each stage of the calculation because you will always get the "correct" answer modulo 2^32 or 2^64. Before returning the result (or before doing division or right bit-shifting) you can normalize back to the standard integer range using something like
import sys
HALF_N = sys.maxint + 1
N = HALF_N * 2
def normalize(value):
return (value + HALF_N) % N - HALF_N
I think the basic idea is sound, but needs some tweaks:
- your function doesn't overflow on
sys.maxint+1
, but it should; sys.maxint
can be exceeded several times over as a result of a single operation;- negative values below
-sys.maxint-1
also need to be considered.
With this in mind, I came up with the following:
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
This function should convert your numbers to look like hardware integers. Depending on your application, you might need to apply this function between each stage of your operations.
def correct(value, bits, signed):
base = 1 << bits
value %= base
return value - base if signed and value.bit_length() == bits else value
The following shortcut functions may come in handy for "casting" values to their appropriate range:
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)
)
As an example of how you might use them, a bug can reproduced that one might see in C. If one were to write a for loop using a byte to print out 0 - 255, the loop might never end. The following program demonstrates this problem:
#! /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()