在cython中,有那么多int种数据类型让我有些纠结.

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

我猜纯python中的int相当于np.int_,那么np.int来自哪里呢?我找不到numpy的文件?还有,既然我们已经有int个,为什么还有np.int_个呢?

在cython中,我猜int在用作cdef intndarray[int]时变成了C类型,而当用作int()时,它仍然是python施法器吗?

np.int_等于C中的long吗?那么cdef longcdef np.int_是一样的吗?

在什么情况下我应该用np.int_t代替np.int呢?例如cdef np.int_t,ndarray[np.int_t].

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

推荐答案

这有点复杂,因为名字根据上下文有不同的含义.

int

  1. 在Python中

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

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

    >>> 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. As Cython type identifier it has another meaning, here it stands for the type int. It's of limited precision (typically 32bits). You can use it as Cython type, for example when defining variables with 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参数.这里的上下文很重要,因此转换为Python int不同于转换为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整数not a NumPy type:

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

My advise regarding np.int: Avoid it whenever possible. 在Python中 code it's equivalent to int and in Cython code it's also equivalent to Pythons int but if used as type-identifier it will probably confuse you and everyone who reads the code! It certainly confused me...

np.int_

实际上,它只有一个含义:它是表示标量NumPy类型的Python type.您可以像Pythons 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代码交换它们!

Notes

在NumPy中还有更多的数字类型,我将包括一个列表,其中包含NumPy dtype和Cython类型标识符,以及这里也可以在Cython中使用的C类型标识符.但它基本上是从the NumPy documentationCython NumPy pxd file取来的:

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_:cnp.npy_boolbint的Cython类型,但是它们目前都不能用于NumPyarray.对于标量,cnp.npy_bool将只是一个无符号整数,而bint将是一个布尔值.不知道那里发生了什么.


1取自NumPy documentation "Data type objects"

内置Python类型

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

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_

C++相关问答推荐

ARM上的Modulo Sim Aarch 64(NEON)

球体—立方体重叠:无、部分或全部?

如何解决C中的严格别名?

为什么可以在typedef之前使用typedef d struct 体?

如果包含路径不存在,我的编译器可以被配置为出错吗?(GCC、MSVC)

struct 上的OpenMP缩减

LONG_DOUBLE_T是否存在(标准C:C23)

每个 struct 变量在C中都有自己的命名空间吗?

在循环中复制与删除相同条件代码的性能

如何在C中使数组变量的值为常量?

将数组插入数组

Printf()在C中打印终止字符之后的字符,我该如何解决这个问题?

C-try 将整数和 struct 数组存储到二进制文件中

从整型转换为浮点型可能会改变其值.

生成一个半RNG,结果用C表示(无随机/随机)

C中的char**v*char[]

不兼容的整数到指针转换传递';char';到类型';常量字符*

我错误地修复了一个错误,想了解原因

#define X Defined(Y) 是有效的 C/C++ 宏定义吗?

clion.我无法理解 Clion 中发生的 scanf 错误