2013-04-02 7 views
5

Czy jest możliwe, a jeśli tak, jak określić rozmiar bitów typów danych całkowitych w Cython?Uzyskaj wielkość liczby całkowitej w czasie kompilacji w Cython

Próbuję zrobić coś takiego, aby uzyskać całkowite rozmiary:

cdef WORD_BITS = 0 
IF sizeof(unsigned long long) == 8: 
    WORD_BITS = 64 
    DEF VECTOR_LENGTH_SHIFT_AMOUNT = 6 
ELSE: 
    WORD_BITS = 32 
    DEF VECTOR_LENGTH_SHIFT_AMOUNT = 5 

ctypedef unsigned long long word_t 

cdef int vector_length(size_t bit_size): 

    cdef size_t size = bit_size >> VECTOR_LENGTH_SHIFT_AMOUNT 
    if size << VECTOR_LENGTH_SHIFT_AMOUNT < bit_size: 
     size += 1 
    return size 

cdef class BitVector(object): 

    cdef size_t length 
    cdef size_t array_size 
    cdef word_t *array 

    def __cinit__(self, size_t size): 
     self.length = size 
     self.array_size = vector_length(size) 
     self.array = <word_t *>calloc(self.array_size, sizeof(word_t)) 

    def __dealloc__(self): 
     free(self.array) 

muszę obsługiwać zarówno pojedyncze kawałki elementów tablicy i samych elementów, a więc mam wiedzieć, ile zawiera ich bitów (aby obliczyć właściwe maski/przesunięcia). Próba skompilowania kodu takiego jak powyższe:

$python setup.py build_ext --inplace 
Compiling bitvector.pyx because it changed. 
Cythonizing bitvector.pyx 

Error compiling Cython file: 
------------------------------------------------------------ 
... 
cimport cython 


# check whether we are running on a 64 or 32 bit architecture. 
cdef WORD_BITS = 0 
IF sizeof(unsigned long long) == 8: 
^
------------------------------------------------------------ 

bitvector.pyx:7:3: Invalid compile-time expression 

Traceback (most recent call last): 
    File "setup.py", line 6, in <module> 
    ext_modules=cythonize('bitvector.pyx') 
    File "/usr/lib/python2.7/dist-packages/Cython/Build/Dependencies.py", line 673, in cythonize 
    cythonize_one(*args[1:]) 
    File "/usr/lib/python2.7/dist-packages/Cython/Build/Dependencies.py", line 737, in cythonize_one 
    raise CompileError(None, pyx_file) 
Cython.Compiler.Errors.CompileError: bitvector.pyx 

Czy istnieje działająca alternatywa?

Wiem, że istnieje stdint.h nagłówek, który powinien określać typy całkowite, ale nie mogę wymyślić sposób, żeby go wykorzystać od:

  • nie wiem, jak sprawdzić, czy typ jest nie zdefiniowano (np. jak piszesz IF uint64_t is not defined: w cytoncie?).
  • Dokumentacja Cythona stwierdza, że ​​tylko rzeczy zdefiniowane przez DEF i kompilator mogą być sprawdzone w IF s, więc wątpię, czy byłbym w stanie użyć w każdym razie stdint.h.

Wydaje się, że jest to niewykonalne w Cython ponieważ kontrola Chcę, aby można przeprowadzić tylko przy kompilacji z C do kodu maszynowego, a nie z Cython do C.

Teraz zastanawiam się: czy możliwe jest napisanie rozszerzenia cythonu w taki sposób, że ten rodzaj sprawdzenia jest dodawany w kodzie źródłowym C?

To znaczy, mogę jakoś napisać:

cdef WORD_BITS = 0 
IF sizeof(unsigned long long) == 8: 
    WORD_BITS = 64 
    DEF VECTOR_LENGTH_SHIFT_AMOUNT = 6 
ELSE: 
    WORD_BITS = 32 
    DEF VECTOR_LENGTH_SHIFT_AMOUNT = 5 

ctypedef unsigned long long word_t 

W taki sposób, aby ten IF „nie są przetwarzane” przez Cython, ale jest on przekazywany przez aw końcowym pliku C jest równoważny kod?

+0

Miałem dokładnie ten sam problem. Czy miałeś szczęście? – PierreBdR

+0

@PierreBdR Niestety nie. Postanowiłem zawsze używać 32-bitowego typu danych, mimo że jest on nieoptymalny w 64-bitowych komputerach. Jeśli chcesz otrzymać odpowiedź, możesz rozważyć dodanie nagrody do tego pytania (możesz ją edytować, jeśli uważasz, że można ją poprawić). – Bakuriu

Odpowiedz

0

Zamiast używać preprocesora do definiowania wielkości i wartości przesunięcia, zmieniłbym nieznacznie swoją funkcję vector_length, aby mogła bezpośrednio używać sizeof. Cython poprawnie przetłumaczy operator sizeof, a kompilator zastąpi aktualny rozmiar typu w podczas kompilacji. Więcej informacji na temat korzystania z sizeof i CHAR_BIT można znaleźć w tej sekcji w dokumentacji glibc, aby uzyskać prawidłowy rozmiar wektorowy: https://www.gnu.org/software/libc/manual/html_node/Width-of-Type.html.

from libc.stdlib cimport calloc, free 
from libc.limits cimport CHAR_BIT 

ctypedef unsigned long long word_t 

cdef size_t vector_length(size_t bit_size): 
    cdef size_t bits_per_word = CHAR_BIT*sizeof(word_t) 
    return (bit_size + bits_per_word - 1)/bits_per_word 

cdef class BitVector(object): 
    cdef size_t length 
    cdef size_t array_size 
    cdef word_t *array 

    def __cinit__(self, size_t size): 
     self.length = size 
     self.array_size = vector_length(size) 
     self.array = <word_t *>calloc(self.array_size, sizeof(word_t)) 

    def __dealloc__(self): 
     free(self.array) 

Warto również zauważyć, że unsigned long long wynosi co najmniej 64 bitów (https://en.wikipedia.org/wiki/C_data_types). Twój kod wydaje się zakładać, że może on być albo 64 lub 32-bitowy, ale w kompilatorze zgodnym ze standardami będzie tylko o 64-bitowy lub więcej.

Powiązane problemy