Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using 32-bit ints and operands

Is it possible to somehow override or overload the standard implementation of ints/numbers in python so that it acts like a 32-bit int.

a: int
a = 4076863488
>>> -218103808

Or is it possible to somehow define a variable that can't change type? Doing something like: x: int? I want to do this because it's annoying to write ctypes.c_int32(n) on every bit operation and assignment. Especially since Python does not use 32 bits bitwise operands.

I know I'm basically trying to change the nature of the language. So maybe I'm asking what you would do if you had to do 32-bit stuff in python.

like image 297
objectnabb Avatar asked Dec 12 '25 07:12

objectnabb


1 Answers

Some options:

  • Use Cython. You can declare a native 32-bit int type there, and you even get the advantage that pure numerical code gets compiled to (very) fast C code.
  • Use a numpy array of a single element: np.zeros((1,), dtype=np.int32). Provided you only ever use in-place operations (+=, *=, etc.), this will work like a 32-bit int type. Do be aware that if you ever use a regular binary operator (e.g. myint + 3), you might be subjected to type promotion or conversion, and the result will no longer be int32.
  • Use ctypes.c_int32. This comes built-in to Python, but supports no mathematical operations so you have to wrap and unwrap yourself (e.g. newval = c_int32(v1.value + v2.value)).
  • Use a library like fixedint (shameless plug), which provides fixed-integer classes that remain fixed size through operations rather than decaying to int. fixedint was specifically designed with fixed-width bitwise math in mind. In this case you would use fixedint.Int32.

Some less desirable options:

  • struct: Throws errors if your input is out of range. You can work around this with unpack('i', pack('I', val & 0xffffffff))[0], but that's really unwieldy.
  • array: Throws errors if you try to store a value out of range. Harder to work around than struct.
  • Manual bitmashing. With an unsigned 32-bit int, this is just a matter of adding & 0xffffffff a lot, which is not too bad. But, Python doesn't have any built-in way to wrap a value to a signed 32-bit int, so you'll have to write your own int32 conversion function and wrap all your operations with it:

    def to_int32(val):
        val &= ((1<<32)-1)
        if val & (1<<31): val -= (1<<32)
        return val
    

Demonstrations of your options:

Cython

cpdef int munge(int val):
    cdef int x
    x = val * 32
    x += 0x7fffffff
    return x

Save as int_test.pyx and compile with cythonize -a -i int_test.pyx.

>>> import int_test
>>> int_test.munge(3)
-2147483553

NumPy

import numpy as np

def munge(val):
    x = val.copy()
    x *= 32
    x += 0x7fffffff
    return x

def to_int32(val):
    return np.array((val,), dtype=np.int32)

print(munge(to_int32(3)))
# prints [-2147483553]

ctypes

from ctypes import c_int32
def munge(val):
    x = c_int32(val.value * 32)
    x = c_int32(x.value + 0x7fffffff)
    return x

print(munge(c_int32(3)))
# prints c_int(-2147483553)

fixedint

import fixedint

def munge(val):
    x = val * 32
    x += 0x7fffffff
    return x

print(munge(fixedint.Int32(3)))
# prints -2147483553
like image 141
nneonneo Avatar answered Dec 13 '25 20:12

nneonneo