2014-10-23 2 views
1

매우 정밀하게 전개되는 계승을 포함하는 계산이 있으므로 임의 정밀도 라이브러리 mpmath을 사용하기로 결심했습니다.mpmath의 Elementwise 연산이 numpy 및 해당 솔루션에 비해 느림

내가 가진 코드는 다음과 같습니다

import numpy as np 
import mpmath as mp 
import time 

a = np.linspace(0, 100e-2, 100) 
b = np.linspace(0, np.pi) 
c = np.arange(30) 

t = time.time() 
M = np.ones([ len(a), len(b), len(c) ]) 
A, B = np.meshgrid(a, b, indexing = 'ij') 
temp = A**2 + B 
temp = np.reshape(temp, [ len(a), len(b), 1 ]) 
temp = np.repeat(temp, len(c), axis = 2) 
M *= temp 
print 'part1:  ', time.time() - t 
t = time.time() 

temp = np.array([ mp.fac(x) for x in c ]) 
temp = np.reshape(temp, [ 1, 1, len(c) ]) 
temp = np.repeat( temp, len(a), axis = 0) 
temp = np.repeat( temp, len(b), axis = 1) 
print 'part2 so far:', time.time() - t 
M *= temp 
print 'part2 finally', time.time() - t 
t = time.time() 

가장 시간이 매우 마지막 줄과 내가 Mfloat s의 무리가 있고 temp가 있기 때문에 그것이 의심이 걸릴 것으로 보인다 건 묶음 : mp.mpf s. 나는 mp.mpf와 함께 M을 초기화하려고 시도했지만 모든 것이 느려졌다.

출력 내가 얻을 수있다 :

part1:  0.00429606437683 
part2 so far: 0.00184297561646 
part2 finally 1.9477159977 

어떤 아이디어를 내가이 속도를 높일 수있는 방법?

답변

2

이 계산 유형에 대해 mpmath보다 훨씬 빠릅니다. 다음 코드는 내 컴퓨터에서 약 12 ​​배 빠르게 실행됩니다.

import numpy as np 
import gmpy2 as mp 
import time 

a = np.linspace(0, 100e-2, 100) 
b = np.linspace(0, np.pi) 
c = np.arange(30) 

t = time.time() 
M = np.ones([len(a), len(b), len(c)]) 
A, B = np.meshgrid(a, b, indexing = 'ij') 
temp = A**2+B 
temp = np.reshape(temp, [len(a), len(b), 1]) 
temp = np.repeat(temp, len(c), axis=2) 
M *= temp 
print 'part1:', time.time() - t 
t = time.time() 

temp = np.array([mp.factorial(x) for x in c]) 
temp = np.reshape(temp, [1, 1, len(c)]) 
temp = np.repeat(temp, len(a), axis=0) 
temp = np.repeat(temp, len(b), axis=1) 
print 'part2 so far:', time.time() - t 
M *= temp 
print 'part2:', time.time() - t 
t = time.time() 

mpmath

는 파이썬으로 작성된 정상적으로의 계산에 파이썬의 기본 정수를 사용합니다. gmpy2을 사용할 수있는 경우 gmpy2에서 제공하는 더 빠른 정수 유형을 사용합니다. gmpy2으로 직접 제공되는 기능 중 하나가 필요하다면 gmpy2을 직접 사용하는 것이 일반적으로 더 빠릅니다.

업데이트 나는 몇 가지 실험을 달렸다. 실제로 일어나는 일은 당신이 기대하는 바가 아닐 수도 있습니다. temp을 계산할 때 값은 정수 (math.factorial, gmpy.fac 또는 gmpy2.fac)이거나 부동 소수점 값 (gmpy2.factorial, mpmath.fac) 일 수 있습니다. numpyM *= temp이라고 계산하면 temp의 모든 값이 64 비트 부동 소수점으로 변환됩니다. 값이 정수인 경우 변환은 OverflowError를 발생시킵니다. 값이 부동 소수점 수이면 변환은 무한대를 반환합니다. cnp.arange(300)으로 변경하고 마지막에 M을 인쇄하여 확인할 수 있습니다. gmpy.fac 또는 math.factorial을 사용하는 경우 OverflowError이 표시됩니다. mpmath.factorial 또는 gmpy2.factorial을 사용하는 경우 OverflowError이 표시되지 않지만 그 결과로 M에는 무한대가 포함됩니다.

OverflowError을 피하려면 부동 소수점 값을 사용하여 temp을 계산해야합니다. 따라서 64 비트 부동 소수점으로 변환하면 무한대가됩니다.

OverflowError이 발생하지 않으면 math.factorial이 가장 빠릅니다.

OverflowError과 무한대를 모두 피하려면, mpmath.mpf 또는 gmpy2.mpfr 부동 소수점 유형 중 하나를 사용해야합니다. (gmpy.mpf을 사용하지 마십시오.)

업데이트 # 2

여기서 200 비트의 정밀도로 gmpy2.mpfr를 사용하는 예이다. c=np.arange(30)을 사용하면 원래 예제보다 ~ 5 배 빠릅니다. OverflowError 또는 무한대를 생성하기 때문에 c = np.arange(300)을 사용하여 보여줍니다. 큰 범위의 총 실행 시간은 원래 코드와 거의 같습니다.

import numpy as np 
import gmpy2 
import time 

from gmpy2 import mpfr 

gmpy2.get_context().precision = 200 

a = np.linspace(mpfr(0), mpfr(1), 100) 
b = np.linspace(mpfr(0), gmpy2.const_pi()) 
c = np.arange(300) 

t = time.time() 
M = np.ones([len(a), len(b), len(c)], dtype=object) 
A, B = np.meshgrid(a, b, indexing = 'ij') 
temp = A**2+B 
temp = np.reshape(temp, [len(a), len(b), 1]) 
temp = np.repeat(temp, len(c), axis=2) 
M *= temp 
print 'part1:', time.time() - t 
t = time.time() 

temp = np.array([gmpy2.factorial(x) for x in c], dtype=object) 
temp = np.reshape(temp, [1, 1, len(c)]) 
temp = np.repeat(temp, len(a), axis=0) 
temp = np.repeat(temp, len(b), axis=1) 
print 'part2 so far:', time.time() - t 
M *= temp 
print 'part2:', time.time() - t 
t = time.time() 

면책 조항 : 나는 gmpy2을 유지한다.

+0

와우! 12 배! 나는 gmpy (이전에'MPMATH_NOGMPY'를 설정 했었습니다)로 실행 시켰지만 기껏해야 40 %의 속도 향상 만했습니다. 또한, 내'mp.libmp.BACKEND'는'gmpy'가 아니며'gmpy2'가 아니라면 어떤 차이가 있습니까? – evan54

+0

죄송합니다. 나는 잘못된 코드를 붙여 넣었다. 나는'gmpy2'를 직접 사용하고 있었다. 잠시 후에 답을 수정하겠습니다. 'gmpy2'는 MPFR (정확하게 반올림 한 실수 부동 소수점)과 MPC (정확한 반올림 된 부동 소수점) 임의 정밀도 라이브러리에 대한 완전한 액세스를 제공합니다. 오래된'gmpy'는 MPFR과 MPC를 지원하지 않습니다. – casevh

+0

흠 ... 나는 당신이 만든 유일한 변화가 계승 함수가 사용된다는 것을 알아 차렸다. 내 코드가 느려지는 것은'mp * fx (x)'연산이 아닌 마지막'M * = temp'입니다. 이 경우 백엔드가 많이 중요합니까? – evan54

관련 문제