与numpy及其解决方案相比,mpmath中的元素运算速度较慢

时间:2014-10-23 23:25:23

标签: python numpy factorial mpmath

我有一些计算涉及阶梯性爆炸很快,所以我决定使用任意精度库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

我有什么想法可以加快速度吗?

1 个答案:

答案 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.factorialgmpy.facgmpy2.fac)或浮点值(gmpy2.factorial,{ {1}})。当mpmath.fac计算numpy时,M *= temp中的所有值都会转换为64位浮点数。如果该值是整数,则转换会引发OverflowError。如果该值是浮点数,则转换返回无穷大。您可以通过将temp更改为c并在结尾处打印np.arange(300)来查看此信息。如果您使用Mgmpy.fac,则会获得math.factorial。如果您使用OverflowErrormpmath.factorial,则无法获得gmpy2.factorial,但结果OverflowError将包含无穷大。

如果您试图避开M,则需要使用浮点值计算OverflowError,以便转换为64位浮点数将导致无穷大。

如果您没有遇到temp,那么OverflowError是最快的选择。

如果您尝试避免math.factorial和无穷大,那么您需要始终使用OverflowErrormpmath.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()