いくつかの変数に型を追加することで、python 関数を cython に相当するものに変換しました。ただし、cython 関数は、元の python 関数とはわずかに異なる出力を生成します。
この投稿でこの違いの理由のいくつかを学びました Cython: unsigned int indexs for numpy array gets different result しかし、この投稿で学んだことを使用しても、まだ cython 関数で同じ結果を生成することはできませんpythonのものとして。
そこで、私が試したことを示す 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 であっても、結果は (PyFloat_FromDouble を使用して) double に強制されます。しかし、配列が python int でインデックス付けされている場合、関数 PyObject_GetItem が代わりに使用され、関数 1 で発生する np.float32_t を取得します。したがって、function1 の式は np.float32_t オペランドを使用して計算されますが、function2 の式は double を使用して計算されます。function1 とはわずかに異なる出力が得られます。
function3は、function1 と同じ出力を得ようとする 2 回目の cython の試みです。ここでは unsigned int インデックスを使用して配列応答にアクセスしますが、結果は np.float32_t 中間変数に残され、計算で使用されます。少し異なる結果が得られます。どうやら、print ステートメントは PyFloat_FromDouble を使用するため、np.float32_t を出力できません。
次に、python関数をcython関数に合わせて変更しようとしました。function4は、各式の少なくとも 1 つのオペランドを float に変換することでこれを達成しようとします。そのため、残りのオペランドも Python float に強制されます。これは cython では double であり、式は function2 のように double で計算されます。関数内の出力は function2 とまったく同じですが、返される値はわずかに異なります?!