cython 中 np.int、np.int_、int 和 np.int_t 之间的差异



我在cython中对这么多int数据类型有点挣扎。

np.int, np.int_, np.int_t, int

我想int在纯python中相当于np.int_,那么np.int从何而来?我找不到来自 numpy 的文档?另外,既然我们已经有了int,为什么np.int_存在?

在cython中,我想当用作cdef intndarray[int]时,int变成C类型,当用作int()时,它仍然是python caster?

np.int_等同于C中的long吗?那么cdef longcdef np.int_相同?

在什么情况下我应该使用np.int_t而不是np.int?例如cdef np.int_tndarray[np.int_t]...

有人可以简要解释一下这些类型的错误使用将如何影响编译的cython代码的性能吗?

这有点复杂,因为名称根据上下文具有不同的含义。

int

  1. 在蟒蛇中

    int通常只是一个Python类型,它具有任意精度,这意味着您可以在其中存储任何可以想象的整数(只要您有足够的内存)。

    >>> int(10**50)
    100000000000000000000000000000000000000000000000000
    
  2. 但是,当您将其用作 NumPy 数组的dtype时,它将被解释为np.int_1。这不是任意精度,它将具有与 Clong相同的大小:

    >>> np.array(10**50, dtype=int)
    OverflowError: Python int too large to convert to C long
    

    这也意味着以下两个是等效的:

    np.array([1,2,3], dtype=int)
    np.array([1,2,3], dtype=np.int_)
    
  3. 作为 Cython 类型标识符 它有另一种含义,这里它代表 c 类型int.它的精度有限(通常为 32 位)。您可以将其用作 Cython 类型,例如在使用cdef定义变量时:

    cdef int value = 100    # variable
    cdef int[:] arr = ...   # memoryview
    

    作为cdefcpdef函数的返回值或参数值:

    cdef int my_function(int argument1, int argument2):
    # ...
    

    作为ndarray的"通用":

    cimport numpy as cnp
    cdef cnp.ndarray[int, ndim=1] val = ...
    

    对于类型转换:

    avalue = <int>(another_value)
    

    可能还有更多。

  4. 在Cython中,但作为Python类型。您仍然可以调用int,您将获得一个"Python int"(任意精度),或者将其用于isinstance或用作np.arraydtype参数。这里的上下文很重要,因此转换为 Pythonint与转换为 C int 不同:

    cdef object val = int(10)  # Python int
    cdef int val = <int>(10)   # C int
    

np.int

实际上这很容易。它只是int的别名:

>>> int is np.int
True

因此,上面的一切都适用于np.int。但是,您不能将其用作类型标识符,除非您在cimported 包上使用它。在这种情况下,它表示 Python 整数类型。

cimport numpy as cnp
cpdef func(cnp.int obj):
return obj

这将期望obj是 Python 整数而不是 NumPy 类型

>>> func(np.int_(10))
TypeError: Argument 'obj' has incorrect type (expected int, got numpy.int32)
>>> func(10)
10

我对np.int的建议:尽可能避免它。在Python代码中,它等同于int,在Cython代码中,它也等同于Pythonint但如果用作类型标识符,它可能会使您和每个阅读代码的人感到困惑!这当然让我感到困惑...

np.int_

实际上它只有一个含义:它是一个表示标量 NumPy 类型的Python 类型。你像 Python 一样使用它int

>>> np.int_(10)        # looks like a normal Python integer
10
>>> type(np.int_(10))  # but isn't (output may vary depending on your system!)
numpy.int32

或者你用它来指定dtype,例如用np.array

>>> np.array([1,2,3], dtype=np.int_)
array([1, 2, 3])

但是您不能将其用作 Cython 中的类型标识符。

cnp.int_t

这是np.int_的类型标识符版本。这意味着您不能将其用作 dtype 参数。但是您可以将其用作cdef声明的类型:

cimport numpy as cnp
import numpy as np
cdef cnp.int_t[:] arr = np.array([1,2,3], dtype=np.int_)
|---TYPE---|                         |---DTYPE---|

此示例(希望)表明带有尾随_t的类型标识符实际上表示使用dtype而不带尾随t的数组的类型。你不能在Cython代码中互换它们!

笔记

NumPy中还有几种数字类型,我将包含一个包含 NumPy dtype 和 Cython 类型标识符的列表,以及 C 类型标识符,这些标识符也可以在此处用于 Cython。但它基本上取自 NumPy 文档和 Cython NumPypxd文件:

NumPy dtype          Numpy Cython type         C Cython type identifier
np.bool_             None                      None
np.int_              cnp.int_t                 long
np.intc              None                      int       
np.intp              cnp.intp_t                ssize_t
np.int8              cnp.int8_t                signed char
np.int16             cnp.int16_t               signed short
np.int32             cnp.int32_t               signed int
np.int64             cnp.int64_t               signed long long
np.uint8             cnp.uint8_t               unsigned char
np.uint16            cnp.uint16_t              unsigned short
np.uint32            cnp.uint32_t              unsigned int
np.uint64            cnp.uint64_t              unsigned long
np.float_            cnp.float64_t             double
np.float32           cnp.float32_t             float
np.float64           cnp.float64_t             double
np.complex_          cnp.complex128_t          double complex
np.complex64         cnp.complex64_t           float complex
np.complex128        cnp.complex128_t          double complex

实际上有用于np.bool_的Cython类型:cnp.npy_boolbint但它们目前都不能用于NumPy数组。对于标量cnp.npy_bool将只是一个无符号整数,而bint将是一个布尔值。不知道那里发生了什么...


1摘自 NumPy 文档"数据类型对象">

内置的 Python 类型

当用于生成 dtype 对象时,几种 python 类型等效于相应的数组标量:

int           np.int_
bool          np.bool_
float         np.float_
complex       np.cfloat
bytes         np.bytes_
str           np.bytes_ (Python2) or np.unicode_ (Python3)
unicode       np.unicode_
buffer        np.void
(all others)  np.object_

>np.int_是默认整数类型(如 NumPy 文档中所定义),但在 64 位系统上,这将是一个C longnp.intc是默认C intint32int64np.int是内置int函数的别名

>>> np.int(2.4)
2
>>> np.int is int  # object id equality
True

cython 数据类型应反映C数据类型,因此cdef int a是一个C int,依此类推。

至于np.int_t,这是 NumPynp.int_数据类型的Cython编译时等效值,np.int64_tCython编译时等效于np.int64

这是对Cython代码中intnp.int_t之间区别的澄清,它们并不相同:

np.int_t映射到 Cython 代码中的long而不是int

这意味着:

  • 在 64 位 Windows(即使用 MSVC 编译)上,int是 4 个字节,但也long(因此np.int_t)。
  • 在 64 位 Linux(即使用 gcc 编译)上,int是 4 个字节,但long(因此np.int_t)是 8 个字节!

np.int-numpy-array 将映射到 Cython 中的np.int_t[:]内存视图,这是正确的,因为以下代码:

import numpy as np
a = np.zeros(1, np.int_)  # or np.zeros(1, np.int)
print(a.itemsize)

将在Windows上产生4(Windows上以字节为单位的long大小),在Linux上产生8

通常,准确指定值的大小是有意义的,例如,通过使用np.int32np.int64,它们将映射到Cython中的np.int32_tnp.int64_t,并且在所有平台上具有相同的大小。

最新更新