通过向一些变量添加类型,我已经将 python 函数转换为 cython 等价物。但是,cython 函数产生的输出与原始 python 函数略有不同。
我在这篇文章 Cython 中了解了这种差异的一些原因:numpy 数组的无符号整数索引给出了不同的结果 但是即使我在这篇文章中学到了什么,我仍然无法让 cython 函数产生相同的结果作为蟒蛇之一。
所以我整理了 4 个函数来说明我尝试过的内容。有人可以帮助揭示为什么每个函数我得到的结果略有不同吗?以及如何获得一个与function1返回相同精确值的cython函数?我在下面发表一些评论:
%%cython
import numpy as np
cimport numpy as np
def function1(response, max_loc):
x, y = int(max_loc[0]), int(max_loc[1])
tmp1 = (response[y,x+1] - response[y,x-1]) / 2*(response[y,x] - min(response[y,x-1], response[y,x+1]))
tmp2 = (response[y,x+1] - response[y,x-1])
tmp3 = 2*(response[y,x] - min(response[y,x-1], response[y,x+1]))
print tmp1, tmp2, tmp3
return tmp1, tmp2, tmp3
cpdef function2(np.ndarray[np.float32_t, ndim=2] response, np.ndarray[np.float64_t, ndim=1] max_loc):
cdef unsigned int x, y
x, y = int(max_loc[0]), int(max_loc[1])
tmp1 = (response[y,x+1] - response[y,x-1]) / 2*(response[y,x] - min(response[y,x-1], response[y,x+1]))
tmp2 = (response[y,x+1] - response[y,x-1])
tmp3 = 2*(response[y,x] - min(response[y,x-1], response[y,x+1]))
print tmp1, tmp2, tmp3
return tmp1, tmp2, tmp3
cpdef function3(np.ndarray[np.float32_t, ndim=2] response, np.ndarray[np.float64_t, ndim=1] max_loc):
cdef unsigned int x, y
x, y = int(max_loc[0]), int(max_loc[1])
cdef np.float32_t tmp1, tmp2, tmp3
cdef np.float32_t r1 =response[y,x+1]
cdef np.float32_t r2 =response[y,x-1]
cdef np.float32_t r3 =response[y,x]
cdef np.float32_t r4 =response[y,x-1]
cdef np.float32_t r5 =response[y,x+1]
tmp1 = (r1 - r2) / 2*(r3 - min(r4, r5))
tmp2 = (r1 - r2)
tmp3 = 2*(r3 - min(r4, r5))
print tmp1, tmp2, tmp3
return tmp1, tmp2, tmp3
def function4(response, max_loc):
x, y = int(max_loc[0]), int(max_loc[1])
tmp1 = (float(response[y,x+1]) - response[y,x-1]) / 2*(float(response[y,x]) - min(response[y,x-1], response[y,x+1]))
tmp2 = (float(response[y,x+1]) - response[y,x-1])
tmp3 = 2*(float(response[y,x]) - min(response[y,x-1], response[y,x+1]))
print tmp1, tmp2, tmp3
return tmp1, tmp2, tmp3
max_loc = np.asarray([ 15., 25.], dtype=np.float64)
response = np.zeros((49,49), dtype=np.float32)
x, y = int(max_loc[0]), int(max_loc[1])
response[y,x] = 0.959878861904
response[y,x-1] = 0.438348740339
response[y,x+1] = 0.753262758255
result1 = function1(response, max_loc)
result2 = function2(response, max_loc)
result3 = function3(response, max_loc)
result4 = function4(response, max_loc)
print result1
print result2
print result3
print result4
结果:
0.0821185777156 0.314914 1.04306030273
0.082118573023 0.314914017916 1.04306024313
0.0821185708046 0.314914017916 1.04306030273
0.082118573023 0.314914017916 1.04306024313
(0.082118577715618812, 0.31491402, 1.043060302734375)
(0.08211857302303427, 0.3149140179157257, 1.0430602431297302)
(0.08211857080459595, 0.3149140179157257, 1.043060302734375)
(0.082118573023034269, 0.31491401791572571, 1.0430602431297302)
function1代表我在原始 python 函数中所做的操作。tmp1 是结果。
function2是我的第一个 cython 版本,它产生的结果略有不同。显然,如果响应数组使用类型化变量 unsigned int 或 int 进行索引,则即使数组的类型是 np.float32_t,结果也会被强制为 double(使用 PyFloat_FromDouble)。但是,如果数组是用 python int 索引的,则使用函数 PyObject_GetItem,我得到 np.float32_t,这就是函数 1 中发生的情况。所以 function1 中的表达式是使用 np.float32_t 操作数计算的,而 function2 中的表达式是使用双精度计算的。我得到的打印结果与 function1 中的略有不同。
function3是我第二次尝试获得与 function1 相同的输出。在这里,我使用 unsigned int 索引来访问数组响应,但结果留在 np.float32_t 中间变量上,然后我在计算中使用它们。我得到的结果略有不同。显然,打印语句将使用 PyFloat_FromDouble,因此它无法打印 np.float32_t。
然后我尝试更改 python 函数以匹配 cython 函数。function4尝试通过在每个表达式中转换为至少一个操作数来实现这一点,因此其余操作数也被强制转换为 python float,这是 cython 中的双精度数,并且表达式使用双精度数计算,如 function2 中一样。函数内部的打印和function2完全一样,但是返回的值略有不同?!