我有一些计算涉及阶梯性爆炸很快,所以我决定使用任意精度库mpmath
。
我的代码如下:
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()
似乎花费最多时间的事情是最后一行,我怀疑是因为M
有一堆float
s而temp
有一堆{mp.mpf
1}}秒。我尝试使用M
初始化mp.mpf
,但随后一切都变慢了。
这是我得到的输出:
part1: 0.00429606437683
part2 so far: 0.00184297561646
part2 finally 1.9477159977
我有什么想法可以加快速度吗?
答案 0 :(得分:2)
gmpy2
明显快于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
是用Python编写的,通常使用Python的本机整数进行计算。如果gmpy2
可用,它将使用gmpy2
提供的更快的整数类型。如果您只需要gmpy2
直接提供的其中一项功能,则直接使用gmpy2
通常会更快。
<强>更新强>
我跑了几个实验。实际发生的事情可能不是您所期望的。计算temp
时,值可以是整数(math.factorial
,gmpy.fac
或gmpy2.fac
)或浮点值(gmpy2.factorial
,{ {1}})。当mpmath.fac
计算numpy
时,M *= temp
中的所有值都会转换为64位浮点数。如果该值是整数,则转换会引发OverflowError。如果该值是浮点数,则转换返回无穷大。您可以通过将temp
更改为c
并在结尾处打印np.arange(300)
来查看此信息。如果您使用M
或gmpy.fac
,则会获得math.factorial
。如果您使用OverflowError
或mpmath.factorial
,则无法获得gmpy2.factorial
,但结果OverflowError
将包含无穷大。
如果您试图避开M
,则需要使用浮点值计算OverflowError
,以便转换为64位浮点数将导致无穷大。
如果您没有遇到temp
,那么OverflowError
是最快的选择。
如果您尝试避免math.factorial
和无穷大,那么您需要始终使用OverflowError
或mpmath.mpf
浮点类型。 (不要试图使用gmpy2.mpfr
。)
更新#2
这是一个使用精度为200位的gmpy.mpf
的示例。使用gmpy2.mpfr
,它比原始示例快约5倍。我使用c=np.arange(30)
显示它,因为它会生成c = np.arange(300)
或无穷大。较大范围的总运行时间与原始代码大致相同。
OverflowError
免责声明:我保留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()
。