使用 32 位整数和操作数

Using 32-bit ints and operands

是否有可能以某种方式覆盖或重载 python 中 ints/numbers 的标准实现,使其像 32 位整数一样工作。

a: int
a = 4076863488
>>> -218103808

或者是否有可能以某种方式定义一个不能改变类型的变量?做类似的事情:x: int? 我想这样做是因为在每个位操作和赋值上写 ctypes.c_int32(n) 很烦人。特别是因为 Python 不使用 32 位按位操作数。

我知道我基本上是在尝试改变语言的本质。所以也许我问的是如果你必须在 python.

中做 32 位的东西你会怎么做

部分选项:

  • 使用 Cython。您可以在那里声明一个本机 32 位 int 类型,您甚至可以获得将纯数字代码编译为(非常)快速的 C 代码的优势。
  • 使用单个元素的 numpy 数组:np.zeros((1,), dtype=np.int32)。如果您只使用就地操作(+=*= 等),这将像 32 位 int 类型一样工作。请注意,如果您曾经使用过常规二元运算符(例如 myint + 3),您可能会进行类型提升或转换,结果将不再是 int32.
  • 使用ctypes.c_int32。这内置于 Python,但不支持数学运算,因此您必须自己包装和解包(例如 newval = c_int32(v1.value + v2.value))。
  • 使用像 fixedint(无耻插件)这样的库,它提供固定整数 类,通过操作保持固定大小而不是衰减到 intfixedint 是专门为固定宽度的按位数学而设计的。在这种情况下,您将使用 fixedint.Int32.

一些不太理想的选项:

  • struct:如果您的输入超出范围,则会抛出错误。您可以使用 unpack('i', pack('I', val & 0xffffffff))[0] 来解决这个问题,但这真的很笨拙。
  • array:如果您尝试存储超出范围的值,则会抛出错误。比 struct.
  • 更难解决
  • 手动 bitmashing。对于 unsigned 32 位 int,这只是添加很多 & 0xffffffff 的问题,这还算不错。但是,Python 没有任何内置方法将值包装成带符号的 32 位整数,因此您必须编写自己的 int32 转换函数并将所有操作包装成它:

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

您的选项演示:

赛通

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

另存为int_test.pyx并用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)

固定整数

import fixedint

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

print(munge(fixedint.Int32(3)))
# prints -2147483553