web-dev-qa-db-fra.com

Différence entre np.int, np.int_, int et np.int_t dans cython?

J'ai un peu de mal avec tant de types de données int dans cython.

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

Je suppose que int en pur python est équivalent à np.int_, Alors d'où vient np.int? Je ne trouve pas le document de numpy? Aussi, pourquoi np.int_ Existe-t-il alors que nous avons déjà int?

Dans cython, je suppose que int devient un type C lorsqu'il est utilisé comme cdef int Ou ndarray[int], Et lorsqu'il est utilisé comme int() il reste le python roulette?

np.int_ Est-il équivalent à long en C? donc cdef long est identique à cdef np.int_?

Dans quelles circonstances dois-je utiliser np.int_t Au lieu de np.int? par exemple. cdef np.int_t, ndarray[np.int_t] ...

Quelqu'un peut-il expliquer brièvement comment une mauvaise utilisation de ces types affecterait les performances du code cython compilé?

33
colinfang

C'est un peu compliqué car les noms ont des significations différentes selon le contexte.

int

  1. En Python

    Le int est normalement juste un Python, il est d'une précision arbitraire, ce qui signifie que vous pouvez stocker n'importe quel entier imaginable à l'intérieur (tant que vous avez suffisamment de mémoire).

    >>> int(10**50)
    100000000000000000000000000000000000000000000000000
    
  2. Cependant, lorsque vous l'utilisez comme dtype pour un tableau NumPy, il sera interprété comme np.int_ 1. Ce qui n'est pas pas de précision arbitraire, il aura la même taille que C long:

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

    Cela signifie également que les deux suivants sont équivalents:

    np.array([1,2,3], dtype=int)
    np.array([1,2,3], dtype=np.int_)
    
  3. En tant qu'identifiant de type Cython, il a une autre signification, ici il représente le type cint. Il est d'une précision limitée (généralement 32 bits). Vous pouvez l'utiliser comme type Cython, par exemple lors de la définition de variables avec cdef:

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

    Comme valeur de retour ou valeur d'argument pour les fonctions cdef ou cpdef:

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

    En tant que "générique" pour ndarray:

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

    Pour le moulage de type:

    avalue = <int>(another_value)
    

    Et probablement beaucoup plus.

  4. En Cython mais comme Python. Vous pouvez toujours appeler int et vous obtiendrez un "Python int" (de précision arbitraire), ou utilisez-le pour isinstance ou comme argument dtype pour np.array. Ici, le contexte est important, donc la conversion en a Python int est différente de la conversion en un C int:

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

np.int

En fait, c'est très simple. C'est juste un alias pour int:

>>> int is np.int
True

Donc, tout ce qui précède s'applique également à np.int. Cependant, vous ne pouvez pas l'utiliser comme identificateur de type, sauf lorsque vous l'utilisez sur le package ed cimport. Dans ce cas, il représente le type entier Python.

cimport numpy as cnp

cpdef func(cnp.int obj):
    return obj

Cela supposera que obj sera un Python entier pas un type NumPy :

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

Mon conseil concernant np.int: Évitez-le autant que possible. Dans Python c'est équivalent à int et dans le code Cython c'est aussi équivalent à Pythons int mais s'il est utilisé comme identificateur de type, cela vous confondra probablement, vous et tout le monde qui lit le code! Cela m'a certainement dérouté ...

np.int_

En fait, il n'a qu'une seule signification: c'est un type Python qui représente un type NumPy scalaire. Vous l'utilisez comme 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

Ou vous l'utilisez pour spécifier le dtype, par exemple avec np.array:

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

Mais vous ne pouvez pas l'utiliser comme identificateur de type en Cython.

cnp.int_t

Il s'agit de la version de l'identificateur de type pour np.int_. Cela signifie que vous ne pouvez pas l'utiliser comme argument dtype. Mais vous pouvez l'utiliser comme type pour les déclarations cdef:

cimport numpy as cnp
import numpy as np

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

Cet exemple (espérons-le) montre que l'identificateur de type avec le _t De fin représente en fait le type d'un tableau utilisant le dtype sans le à la fin t. Vous ne pouvez pas les échanger en code Cython!

Remarques

Il existe plusieurs autres types numériques dans NumPy. Je vais inclure une liste contenant le dtype NumPy et l'identificateur de type Cython et l'identifiant de type C qui pourraient également être utilisés en Cython ici. Mais il est essentiellement tiré de la documentation NumPy et du fichier Cython NumPy pxd :

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

En fait, il existe des types Cython pour np.bool_: cnp.npy_bool Et bint mais les deux ne peuvent pas être utilisés pour les tableaux NumPy actuellement. Pour les scalaires, cnp.npy_bool Sera simplement un entier non signé tandis que bint sera un booléen. Je ne sais pas ce qui se passe là-bas ...


1 Tiré de la documentation NumPy "Objets de type de données"

Intégré Python

Plusieurs types python sont équivalents à un scalaire de tableau correspondant lorsqu'ils sont utilisés pour générer un objet 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_
30
MSeifert

np.int_ est le type d'entier par défaut ( tel que défini dans les documents NumPy ), sur un système 64 bits, ce serait un C long. np.intc est la valeur par défaut C int Soit int32 ou int64. np.int est un alias de la fonction intégrée int

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

Les types de données cython doivent refléter les types de données C, donc cdef int a est un C int etc.

Pour ce qui est de np.int_t c'est l'équivalent de temps de compilation Cython de NumPy np.int_ Type de données, np.int64_t est l'équivalent en temps de compilation de Cython de np.int64

7
Matti Lyra