Python MPFR除法比本机整数除法快吗?
我一直认为整数除法比浮点除法快,但我做了一些测试,似乎证明了这一点Python MPFR除法比本机整数除法快吗?,python,mpfr,gmpy,Python,Mpfr,Gmpy,我一直认为整数除法比浮点除法快,但我做了一些测试,似乎证明了这一点 import gmpy2, time, math digits = 100000 scale = 10**digits # Decimal precision gmpy2.get_context().precision = int(math.log2(10) * digits) # Binary precision def start_timer(): global start_time start
import gmpy2, time, math
digits = 100000
scale = 10**digits # Decimal precision
gmpy2.get_context().precision = int(math.log2(10) * digits) # Binary precision
def start_timer():
global start_time
start_time = time.time()
def print_timer():
print("%s s" % (time.time() - start_time))
start_timer()
for i in range(1000):
x = scale // 3
print_timer()
start_timer()
for i in range(1000):
x = gmpy2.mpfr(1) / 3
print_timer()
start_timer()
for i in range(1000):
x = gmpy2.mpfr(1) / gmpy2.mpfr(3)
print_timer()
整数除法耗时0.17秒,mpfr除法耗时0.06秒,两个浮点数之间的除法耗时15.56秒
我的问题是:
在CPU上,浮点除法通常比整数除法快。有人可能会推测,这与FPU为此操作进行了更优化有关,或者浮点表示使除法更容易。但不管是什么原因都改变不了事实。最后,对你的第二个和第三个问题获得具体答案的唯一方法就是测试它。是的,你的测试在我看来还行
如果我不得不大胆猜测,我认为将MPFR数除以整数的情况更快,因为GMP在计算除法时可以利用其有限的精度优势。浮点除法通常比CPU上的整数除法更快。有人可能会推测,这与FPU为此操作进行了更优化有关,或者浮点表示使除法更容易。但不管是什么原因都改变不了事实。最后,对你的第二个和第三个问题获得具体答案的唯一方法就是测试它。是的,你的测试在我看来还行
如果我不得不大胆猜测,我认为将MPFR数除以整数的情况更快,因为GMP在计算除法时可以利用其有限的精度优势。我使用IPython计算一些简短的示例,然后我将尝试解释结果
from gmpy2 import mpfr, get_context
get_context().precision=1000
a=mpfr(1);b=mpfr(3)
%timeit a/b
1000000 loops, best of 3: 669 ns per loop
%timeit a/3
1000000 loops, best of 3: 464 ns per loop
get_context().precision=10000
a=mpfr(1);b=mpfr(3)
%timeit a/b
100000 loops, best of 3: 12.9 µs per loop
%timeit a/3
1000000 loops, best of 3: 1.33 µs per loop
get_context().precision=100000
a=mpfr(1);b=mpfr(3)
%timeit a/b
1000 loops, best of 3: 505 µs per loop
%timeit a/3
100000 loops, best of 3: 8.13 µs per loop
请注意,随着精度的提高,a/b
的运行时间比a/3
的增长更快。当计算a/b
时,MPFR使用两个值的全部精度,运行时间(大致)为O(n*ln(n))。当计算a/3
时,MPFR使用短而精确的3表示,运行时间(大致)为O(n)。这就解释了为什么a/b
要比a/3
慢以获得高精度。(n是a
的长度,单位为位。)
当Python计算scale//3
时,它利用了这样一个事实,即3将适合单个数字
,并且运行时间在scale
的长度上是线性的。这实际上与a/3
的计算相同,但由于底层GMP库比Python快,a/3
的计算速度比scale//3
快
下面是Python和GMP之间性能差异的一个简短示例
from gmpy2 import mpz
scale = 10**100000
%timeit scale//3
10000 loops, best of 3: 162 µs per loop
scale = mpz(scale)
%timeit scale//3
100000 loops, best of 3: 19 µs per loop
当您比较a/b
和a/3
时,您是在测量n
按n
划分和n
按k
划分之间的绩效。(n
是a
的长度,以位为单位,k
比n
小得多)当您比较scale//3
和'a/3'时,您是在比较简单、直接的除法实现和高度优化的实现
实现说明:在当前不稳定的开发分支中,a/3
直接调用mpfr\u div\u ui
。这消除了MPFR创建临时对象的过程。这将提高性能,如下所示
from gmpy2 import mpfr, get_context
get_context().precision=1000
a=mpfr(1);b=mpfr(3)
%timeit a/b
1000000 loops, best of 3: 593 ns per loop
%timeit a/3
1000000 loops, best of 3: 231 ns per loop
get_context().precision=10000
a=mpfr(1); b=mpfr(3)
%timeit a/b
100000 loops, best of 3: 12.7 µs per loop
%timeit a/3
1000000 loops, best of 3: 927 ns per loop
get_context().precision=100000
a=mpfr(1);b=mpfr(3)
%timeit a/b
1000 loops, best of 3: 505 µs per loop
%timeit a/3
100000 loops, best of 3: 6.77 µs per loop
我用IPython来计时一些简短的例子,然后我将尝试解释结果
from gmpy2 import mpfr, get_context
get_context().precision=1000
a=mpfr(1);b=mpfr(3)
%timeit a/b
1000000 loops, best of 3: 669 ns per loop
%timeit a/3
1000000 loops, best of 3: 464 ns per loop
get_context().precision=10000
a=mpfr(1);b=mpfr(3)
%timeit a/b
100000 loops, best of 3: 12.9 µs per loop
%timeit a/3
1000000 loops, best of 3: 1.33 µs per loop
get_context().precision=100000
a=mpfr(1);b=mpfr(3)
%timeit a/b
1000 loops, best of 3: 505 µs per loop
%timeit a/3
100000 loops, best of 3: 8.13 µs per loop
请注意,随着精度的提高,a/b
的运行时间比a/3
的增长更快。当计算a/b
时,MPFR使用两个值的全部精度,运行时间(大致)为O(n*ln(n))。当计算a/3
时,MPFR使用短而精确的3表示,运行时间(大致)为O(n)。这就解释了为什么a/b
要比a/3
慢以获得高精度。(n是a
的长度,单位为位。)
当Python计算scale//3
时,它利用了这样一个事实,即3将适合单个数字
,并且运行时间在scale
的长度上是线性的。这实际上与a/3
的计算相同,但由于底层GMP库比Python快,a/3
的计算速度比scale//3
快
下面是Python和GMP之间性能差异的一个简短示例
from gmpy2 import mpz
scale = 10**100000
%timeit scale//3
10000 loops, best of 3: 162 µs per loop
scale = mpz(scale)
%timeit scale//3
100000 loops, best of 3: 19 µs per loop
当您比较a/b
和a/3
时,您是在测量n
按n
划分和n
按k
划分之间的绩效。(n
是a
的长度,以位为单位,k
比n
小得多)当您比较scale//3
和'a/3'时,您是在比较简单、直接的除法实现和高度优化的实现
实现说明:在当前不稳定的开发分支中,a/3
直接调用mpfr\u div\u ui
。这消除了MPFR创建临时对象的过程。这将提高性能,如下所示
from gmpy2 import mpfr, get_context
get_context().precision=1000
a=mpfr(1);b=mpfr(3)
%timeit a/b
1000000 loops, best of 3: 593 ns per loop
%timeit a/3
1000000 loops, best of 3: 231 ns per loop
get_context().precision=10000
a=mpfr(1); b=mpfr(3)
%timeit a/b
100000 loops, best of 3: 12.7 µs per loop
%timeit a/3
1000000 loops, best of 3: 927 ns per loop
get_context().precision=100000
a=mpfr(1);b=mpfr(3)
%timeit a/b
1000 loops, best of 3: 505 µs per loop
%timeit a/3
100000 loops, best of 3: 6.77 µs per loop
关于gnumpfr实现的一个注意事项(我是MPFR开发人员,但我没有真正研究除法):选择最佳的乘法和除法算法非常困难,因为有各种参数(输入和输出的精度,以及输入是否可以用更小的精度表示,特别是因为后面的零),有些情况可能比其他情况更难舍入。此外,算法因此可能会从一个版本更改为另一个版本,im