我试图规范化存储为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不支持/ =操作(需要循环)
答案 0 :(得分:1)
因为这并不是Cython要做任何特别的事情或根本没有优化的事情。它所做的只是在Numpy数组上调用__Pyx_PyNumber_InPlaceDivide
,这会调用Numpy数组的__idiv__
运算符。
由于它正在调用Python运算符,因此需要传递Python对象作为第二个参数,因此需要将double转换为Python float。
几乎可以肯定Numpy __idiv__
运算符是用C编写的,因此可能相当快(尽管有一点点开销调用它),因此Cython在执行任何事情(除了委托Numpy的代码之外)没有太多价值。
Memoryviews没有定义整个数组的运算符(它们只是访问内存的方式,因此不必对有意义的数学运算进行任何声明),因此,它不起作用的事实与Cython的处理方式一致这些运营商。