6

Cythonの整数データ型のサイズをビット単位で決定することは可能ですか?

整数のサイズを取得するために、次のようなことをしようとしています:

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)

配列の要素の単一ビットと要素自体の両方を処理する必要があるため、適切なマスク/シフトを計算するために、それらに含まれるビット数を知る必要があります。上記のようなコードをコンパイルしようとすると、次のようになります。

$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

有効な代替手段はありますか?

整数型を定義する必要があるヘッダーがあることは知っていstdint.hますが、それを使用する方法が思い浮かびません:

  • 型が定義されていないかどうかを確認する方法がわかりません (たとえば、cython ではどのように記述ますIF uint64_t is not defined:か?)。
  • DEFCython のドキュメントには、およびコンパイラによって定義されたもののみがIFs でチェックできると記載されているため、とにかく使用できるとは思えませstdint.hん。

これは、Cython から C ではなく、C からマシン コードにコンパイルする場合にのみ実行できるチェックであるため、Cython では実行できないようです。

この種のチェックが C ソース コードに追加されるような方法で cython 拡張機能を作成することは可能でしょうか?

つまり、どういうわけか書くことができます:

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

これIFはCythonによって「処理されません」が、通過され、最終的なCファイルに同等のコードがありますか?

4

1 に答える 1

2

プリプロセッサを使用してサイズとシフト値を定義する代わりに、直接vector_length使用できるように関数を少し変更しますsizeof。Cython はsizeof演算子を正しく変換し、コンパイラはコンパイル時に型の実際のサイズを置き換えます。正しいベクトル サイズの使用sizeofと取得の詳細については、glibc ドキュメントの次のセクションを参照してください: https://www.gnu.org/software/libc/manual/html_node/Width-of-Type.htmlCHAR_BIT

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)

unsigned long long少なくとも 64 ビットであることも注目に値します ( https://en.wikipedia.org/wiki/C_data_types )。あなたのコードは、64ビットまたは32ビットのいずれかであると想定しているようですが、標準準拠のコンパイラでは、64ビット以上になるだけです。

于 2014-11-23T00:26:29.727 に答える