为什么cypys的numpy数组就地分割使用对python浮点数的转换?

时间:2019-03-06 16:01:43

标签: numpy cython

我试图规范化存储为numpy数组的矢量,但是cython -a在此代码中显示了对Python值的意外转换。

最小示例:

import numpy as np
cimport cython
cimport numpy as np

@cython.wraparound(False)
@cython.boundscheck(False)
cdef vec_diff(np.ndarray[double, ndim=1] vec1, double m):
    vec1/=m
    return vec1

使用-a选项运行的Cython 0.29.6为行vec1/=m生成以下代码:

  __pyx_t_1 = PyFloat_FromDouble(__pyx_v_m); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 8, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_PyNumber_InPlaceDivide(((PyObject *)__pyx_v_vec1), __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 8, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  if (!(likely(((__pyx_t_2) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_2, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 8, __pyx_L1_error)
  __pyx_t_3 = ((PyArrayObject *)__pyx_t_2);
  {
    __Pyx_BufFmt_StackElem __pyx_stack[1];
    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_vec1.rcbuffer->pybuffer);
    __pyx_t_4 = __Pyx_GetBufferAndValidate(&__pyx_pybuffernd_vec1.rcbuffer->pybuffer, (PyObject*)__pyx_t_3, &__Pyx_TypeInfo_double, PyBUF_FORMAT| PyBUF_STRIDES, 1, 0, __pyx_stack);
    if (unlikely(__pyx_t_4 < 0)) {
      PyErr_Fetch(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7);
      if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_vec1.rcbuffer->pybuffer, (PyObject*)__pyx_v_vec1, &__Pyx_TypeInfo_double, PyBUF_FORMAT| PyBUF_STRIDES, 1, 0, __pyx_stack) == -1)) {
        Py_XDECREF(__pyx_t_5); Py_XDECREF(__pyx_t_6); Py_XDECREF(__pyx_t_7);
        __Pyx_RaiseBufferFallbackError();
      } else {
        PyErr_Restore(__pyx_t_5, __pyx_t_6, __pyx_t_7);
      }
      __pyx_t_5 = __pyx_t_6 = __pyx_t_7 = 0;
    }
    __pyx_pybuffernd_vec1.diminfo[0].strides = __pyx_pybuffernd_vec1.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_vec1.diminfo[0].shape = __pyx_pybuffernd_vec1.rcbuffer->pybuffer.shape[0];
    if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 8, __pyx_L1_error)
  }
  __pyx_t_3 = 0;
  __Pyx_DECREF_SET(__pyx_v_vec1, ((PyArrayObject *)__pyx_t_2));
  __pyx_t_2 = 0;

第一行__pyx_t_1 = PyFloat_FromDouble(__pyx_v_m);的{​​{1}}用深红色突出显示。

鉴于我已经告诉cython,该数组包含双精度值,为什么它必须转换为python float?

注意:Memoryviews不支持/ =操作(需要循环)

1 个答案:

答案 0 :(得分:1)

因为这并不是Cython要做任何特别的事情或根本没有优化的事情。它所做的只是在Numpy数组上调用__Pyx_PyNumber_InPlaceDivide,这会调用Numpy数组的__idiv__运算符。

由于它正在调用Python运算符,因此需要传递Python对象作为第二个参数,因此需要将double转换为Python float。

几乎可以肯定Numpy __idiv__运算符是用C编写的,因此可能相当快(尽管有一点点开销调用它),因此Cython在执行任何事情(除了委托Numpy的代码之外)没有太多价值。


Memoryviews没有定义整个数组的运算符(它们只是访问内存的方式,因此不必对有意义的数学运算进行任何声明),因此,它不起作用的事实与Cython的处理方式一致这些运营商。