использование итератора в Cython - PullRequest
0 голосов
/ 16 сентября 2018

Я пытаюсь изучить Cython, и я изменил пример, найденный здесь .

#pyx file

import numpy as np
cimport numpy as np
import cython

np.import_array()

def test1(a):
    out = np.empty(a.shape, np.double)

    cdef np.flatiter ita = np.PyArray_IterNew(a)
    cdef np.flatiter ito = np.PyArray_IterNew(out)

    cdef double value

    cdef double i
    i = 0.0

    while np.PyArray_ITER_NOTDONE(ita):

        value = (<double*>np.PyArray_ITER_DATA(ita))[0]

        print(ita)  # for debugging
        print(value,i)  # for debugging

        value = value + i

        (<double*>np.PyArray_ITER_DATA(ito))[0] = value

        i += 1.0

        np.PyArray_ITER_NEXT(ita)
        np.PyArray_ITER_NEXT(ito)

    return out

Поэтому я ожидаю, что функция добавит каждый элемент входного массива на i, где значение i увеличивается на единицу каждый раз, когда итератор переходит к следующему элементу. Когда я запускаю функцию с a=np.arange(10), оператор print показывает что-то вроде:

(2.121995791e-314, 0.0)
(<numpy.flatiter object at 0x0000024A2CE27B20>)

(4.2439915824e-314, 1.0)
(<numpy.flatiter object at 0x0000024A2CE27B20>)

(6.365987374e-314, 2.0)
(<numpy.flatiter object at 0x0000024A2CE27B20>)

(8.4879831653e-314, 3.0)
(<numpy.flatiter object at 0x0000024A2CE27B20>)
# rest not shown here

это не то, что я ожидаю, так как кажется, что итератор все еще указывает на тот же элемент массива, и значение, возвращаемое value, по существу равно нулю, но не значения a (число 0 -9). Но итератор, похоже, останавливается в конце, поскольку функция успешно завершается, а возвращаемый массив имеет ту же форму, что и a.

Итак, мой вопрос:

  1. Что на самом деле означает строка value = (<double*>np.PyArray_ITER_DATA(ita))[0]? <double*> объявляет тип указателя? np.PyArray_ITER_DATA это то, что говорит API. Тогда как насчет [0]?

  2. Что я не так понял и как изменить код? Если a=np.arange(2,8), то test1(a) должно дать array([ 2, 4, 6, 8, 10, 12]).

1 Ответ

0 голосов
/ 16 сентября 2018

Проблема заключалась в том, что arange дает вам массив int по умолчанию, который вы затем интерпретируете, как если бы это был массив double (маленькие целые числа, неверно истолкованные как двойные, часто составляют 1e-300 ish, поэтомуэто обычно хорошая подсказка).В идеале вы должны убедиться, что вы проверили dtype в функции.

Чтобы ответить на ваши дальнейшие вопросы:

print(ita) печатает адрес объекта итератора, а не данные, которые он в данный моментполучающий доступ.Поэтому он всегда показывает один и тот же адрес.

np.PyArray_ITER_DATA(ita) получает указатель на адрес текущего бита данных.Поскольку он спроектирован как универсальный интерфейс для любого массива, мы не знаем тип, поэтому это void*.<double*> вы говорите Cython, что этот указатель на самом деле указывает на double.[0] ищет значение, сохраненное в этом указателе

...