2013-03-13 7 views
4

일부 변수에 형식을 추가하여 파이썬 함수를 파이썬 함수로 변환했습니다. 그러나 cython 함수는 원래 파이썬 함수보다 약간 다른 출력을 생성합니다.cython 함수 출력이 파이썬 함수 출력과 약간 다릅니다.

나는 Cython: unsigned int indices for numpy arrays gives different result 그러나 심지어 나는 여전히 파이썬과 동일한 결과를 생성하는 사이 썬 기능을 얻을 수없는이 게시물에서 배운 내용과이 게시물의 차이에 대한 이유의 일부를 배웠다 .

그래서 내가 시도한 것을 보여주는 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) 

기능 1 내가 내 원래 파이썬 기능에서했던 작업을 나타냅니다 나는 울부 짖는 소리 몇 가지 의견을. tmp1이 결과입니다.

function2은 약간 다른 결과를 생성하는 내 첫번째 cython 버전입니다. 분명히, 응답 배열이 형식화 된 변수 인 unsigned int 또는 int로 인덱싱되면 배열의 유형이 np.float32_t 인 경우에도 결과는 PyFloat_FromDouble을 사용하여 double로 강제 변환됩니다. 그러나 배열이 파이썬 int로 인덱싱 된 경우 PyObject_GetItem 함수가 대신 사용되며 function1에서 발생하는 np.float32_t를 얻습니다. 따라서 function1의 표현식은 np.float32_t 피연산자를 사용하여 계산되지만 function2의 표현식은 double을 사용하여 계산됩니다. function1보다 약간 다른 인쇄물이 나옵니다.

function3은 function1과 동일한 출력을 얻으려는 두 번째 cython 시도입니다. 여기 서명되지 않은 int 인덱스를 사용하여 배열 응답에 액세스하지만 그 결과는 계산에 사용되는 np.float32_t 중간 변수에 남아 있습니다. 나는 약간 다른 결과를 얻는다. 분명히 print 문은 PyFloat_FromDouble을 사용하므로 np.float32_t를 인쇄 할 수 없습니다.

그런 다음 파이썬 함수를 cython과 일치하도록 변경하려고했습니다. function4은 각 표현식에서 하나 이상의 피연산자를 부동 소수점으로 변환하여이를 수행하려고하므로 나머지 피연산자도 python float로 강제 변환됩니다. 이는 cython에서 double이고 expression은 function2 에서처럼 double로 계산됩니다. 함수 내의 print는 function2와 똑같지 만 반환 된 값은 약간 다릅니다.

+2

차이는 (a 억 한 부분)는 약 10^-9 최대이다. 왜 다른 구현물이 그 정도의 크기만큼 다른지 놀랍 니? (어떤 응용 프로그램에서 문제가 발생합니까?) –

+0

hex(),'print ",".join ([result4의 x에 대해 x.hex()])로 플로트 값을 인쇄하십시오. – HYRY

+1

함수 1은'tmp1','tmp2','tmp3'에 파이썬'float' (IEEE double) 값을 사용합니다. 함수 3은이를 명시 적으로'np.float32_t' (IEEE single)로 선언합니다. 그들이 어떻게 똑같은 것을 돌려 줄 수 있을까요? 중간 유형을 일치 시키려고하지만, 완전히 다른 최종 유형을 사용하면 목적을 달성 할 수 없습니다. – abarnert

답변

2

정밀도가 7.225 자리 인 단 정밀도 부동 소수점을 사용하는 경우 강제 변환의 작은 분산이 중요하지 않을 것으로 예상됩니다. 객체를 사용하면 인덱스가, 사이 썬의 (a C float을 위해 단지 형식 정의입니다 아닌 np.float32_t,)를 np.float32 스칼라 개체를 가져 PyObject_GetItem를 사용하는 경우

function2의 당신의 설명을 명확히하기 위해. 대신에 버퍼에 직접 색인을 만들고 Cython에 객체가 필요하면 PyFloat_FromDouble을 호출합니다. 입력하지 않았으므로 tmp1, tmp2tmp3을 할당 할 객체가 필요합니다.

반면에 tmp 변수에 입력했지만 float 개체를 만들어야 결과를 인쇄 할 수 있습니다.

>>> type(np.float32(1)/2) 
<type 'numpy.float64'> 
: 당신은 예를 들어 2로 나눌 때 그건 그렇고, 당신은 np.float64 그 결과를 승진, function1에서

: 당신이 대신 NumPy와 ndarray (아래 참조)를 사용하는 경우, 당신은 문제가되지 않습니다

대 모든 작업이 defcpdef 기능을 모두 float32을인지 확인하더라도

>>> type(np.float32(1)/np.float32(2)) 
<type 'numpy.float32'> 

는, 최종 결과는 여전히 COM에 둘 사이에 다를 수 있습니다 쌓여있는 확장 모듈. 다음 예제에서는 function1의 중간 결과가 모두 개체 인 것을 확인했습니다. function2의 생성 된 C에서 double (또는 동등한 typedef)에 캐스트가 없다는 것을 확인했습니다. 그러나이 두 기능은 여전히 ​​약간 다른 결과를 만들어냅니다. 이유를 알아 내기 위해 컴파일 된 어셈블리로 들어가야 할 수도 있지만, 아마도 간단한 것을 간과 할 수 있습니다.

def function1(response, max_loc):  
    tmp = np.zeros(3, dtype=np.float32) 
    x, y = int(max_loc[0]), int(max_loc[1]) 
    tmp[0] = (((response[y,x+1] - response[y,x-1])/np.float32(2)) * 
      (response[y,x] - min(response[y,x-1], response[y,x+1]))) 
    tmp[1] = response[y,x+1] - response[y,x-1] 
    tmp[2] = 2*(response[y,x] - min(response[y,x-1], response[y,x+1])) 

    print tmp[0], tmp[1], tmp[2] 
    return tmp 

cpdef function2(np.ndarray[np.float32_t, ndim=2] response, max_loc): 
    cdef np.ndarray[np.float32_t, ndim=1] tmp = np.zeros(3, dtype=np.float32) 
    cdef unsigned int x, y 
    x, y = int(max_loc[0]), int(max_loc[1]) 
    tmp[0] = (((response[y,x+1] - response[y,x-1])/<np.float32_t>2) * 
      (response[y,x] - min(response[y,x-1], response[y,x+1]))) 
    tmp[1] = response[y,x+1] - response[y,x-1] 
    tmp[2] = 2*(response[y,x] - min(response[y,x-1], response[y,x+1])) 

    print tmp[int(0)], tmp[int(1)], tmp[int(2)] 
    return tmp 

비교 :

>>> function1(response, max_loc) 
0.0821186 0.314914 1.04306 
array([ 0.08211858, 0.31491402, 1.0430603 ], dtype=float32) 

>>> function2(response, max_loc) 
0.0821186 0.314914 1.04306 
array([ 0.08211857, 0.31491402, 1.0430603 ], dtype=float32) 
+0

답장을 보내 주셔서 감사합니다. 사실, 올바른 장소에 괄호를 넣은 후에 (tmp2는 분자로, tmp3은 분모이므로 내 tmp1에는 괄호가 없습니다.) 함수 1과 함수 2에 대해 동일한 정확한 결과를 얻습니다. 나는 cython 문서에서 명확하지 않은 몇 가지 세부 사항이 있음을 알 수있다. 타입 (np.float32 (1)/2) == <타입 'numpy.float64'>는 약간의 개찰판이고, 하나의 피연산자는 np.float32 객체이고 다른 하나는 int 객체이며 그 결과는 둘 다 아닙니다 !! – martinako

+0

이제는 결과를 맞출 수 있습니다. 그러나 이것은 파이썬 버전을 작성한 다음 해당 파이썬 버전을 얻는 대신 파이썬과 cython을 모두 염두에두고 작성해야 함을 의미합니다. 나는 순수한 파이썬 모드에서이 약간의 차이점이있을 것이라고 생각한다. – martinako

2

의 비교 해보자

  • function1 통해 float32_t 모든 방법을 유지합니다.
  • function2은 색인 생성시 float으로 변환하고 중간 단계는 float으로 변경 한 다음 float32_t으로 다시 변환하여 최종 결과를 얻습니다.
  • function3float으로 변환되지만 바로 다음 단계 인 float32_t으로 즉시 돌아갑니다.
  • function4float으로 변환되고 중간 단계는 float으로 최종 결과를 반환합니다. 당신이 유형을 보면, 그것은 간단합니다 function4function2과 같은 일을 인쇄하지만 다른 뭔가를 반환하는 이유에 관해서는

. 값이 분명히 비슷하므로 같은 방법으로 print이 발생하지만 비슷하게 repr에 근접하지는 않습니다. 그들이 같은 유형이 아니라면 놀라운 일이 아닙니다.

관련 문제