Я преобразовал функцию python в эквивалент cython, добавив типы к некоторым переменным. Однако функция cython создает несколько отличный результат, чем исходная функция python.Выход функции cython немного отличается от вывода функции python
Я узнал некоторые из причин этой разницы в этом посте Cython: unsigned int indices for numpy arrays gives different result Но даже с тем, что я узнал в этом посте я до сих пор не могу получить функцию Cython производить те же результаты, что и питон один ,
Итак, я собрал 4 функции, иллюстрирующие то, что я пробовал. Может ли кто-нибудь помочь раскрывать, почему я получаю несколько разные результаты для каждой функции? и как получить функцию cython, которая возвращает те же точные значения, что и function1? Я делаю некоторые комментарии ниже:
%%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 представляет операции, которые я сделал в моей первоначальной функции питона. Результат tmp1.
function2 - моя первая версия cython, которая дает несколько разные результаты. По-видимому, если массив ответов индексируется с типизированной переменной, unsigned int или int, результат принуждается к двойному (используя PyFloat_FromDouble), даже если тип массива - np.float32_t. Но если массив индексируется с помощью python int, вместо него используется функция PyObject_GetItem, и я получаю np.float32_t, что и происходит в функции1. Таким образом, выражения в функции 1 вычисляются с использованием np.float32_t операндов, тогда как выражения в функции2 вычисляются с использованием удвоений. Я получаю немного другой отпечаток, чем в функции1.
function3 - моя вторая попытка cython, пытающаяся получить тот же результат, что и функция1. Здесь я использую unsigned int индексы для доступа к ответу массива, но результаты остаются на промежуточных переменных np.float32_t, которые затем используются в вычислении. Я получаю немного другой результат. Очевидно, оператор print будет использовать PyFloat_FromDouble, поэтому он не сможет напечатать файл np.float32_t.
Затем я попытался изменить функцию python в соответствии с cython. function4 пытается достичь этого путем преобразования в поплавок по меньшей мере одного операнда в каждом выражении, чтобы остальные операнды были принудительно применены к float python, который является двойным в цитоне, а выражение вычисляется с удвоением, как в функции2. Отпечатки внутри функции точно такие же, как функция2, но возвращаемые значения немного отличаются ?!
Разница составляет около 10^-9 максимум (одна часть на миллиард). Почему вы удивлены, что разные реализации будут отличаться от такого масштаба? (И в каком приложении это вызовет проблему?) –
напечатайте ваши значения float с помощью hex(), 'print", ".join ([x.hex() для x в result4])'. – HYRY
Функция 1 использует значения Python 'float' (IEEE double) для' tmp1', 'tmp2' и' tmp3'. Функция 3 явно объявляет их как «np.float32_t» (одиночный IEEE). Как они могли вернуть одно и то же? Получение промежуточных типов для соответствия, но затем использование совершенно разных конечных типов поражает цель. – abarnert