Использование 32-битных целых и операндов - PullRequest
0 голосов
/ 04 ноября 2018

Можно ли как-то переопределить или перегрузить стандартную реализацию чисел / чисел в python, чтобы она действовала как 32-битное целое.

a: int
a = 4076863488
>>> -218103808

Или можно как-то определить переменную, которая не может изменить тип? Делать что-то вроде: x: int? Я хочу сделать это, потому что раздражает запись ctypes.c_int32(n) на каждую битовую операцию и присваивание. Тем более что Python не использует 32-битные побитовые операнды.

Я знаю, что в основном пытаюсь изменить природу языка. Поэтому, возможно, я спрашиваю, что бы вы сделали, если бы вам пришлось делать 32-битные вещи в Python.

1 Ответ

0 голосов
/ 04 ноября 2018

Некоторые опции:

  • Используйте 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 (бесстыдный плагин), которая предоставляет классы с фиксированными целыми числами, которые остаются фиксированного размера посредством операций, а не затухают до int. fixedint был специально разработан с учетом побитовой математики фиксированной ширины. В этом случае вы бы использовали fixedint.Int32.

Некоторые менее желательные варианты:

  • struct: выдает ошибки, если ваш ввод выходит за пределы диапазона. Вы можете обойти это с помощью unpack('i', pack('I', val & 0xffffffff))[0], но это действительно громоздко.
  • array: выдает ошибки, если вы пытаетесь сохранить значение вне диапазона. Труднее работать, чем struct.
  • Ручная битмашинг. Для 32-битного целого без знака это просто вопрос добавления & 0xffffffff, что не так уж и плохо. Но в Python нет встроенного способа обернуть значение в 32-битное целое со знаком, поэтому вам придется написать собственную функцию преобразования int32 и обернуть все свои операции с ней:

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

Демонстрация ваших вариантов:

Cython

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)

fixedint

import fixedint

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

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