对于我的一个类,我最近遇到了一个ruby和python实现,使用miller-rabin算法来识别20到29000之间的素数。我很好奇为什么,即使它们看起来是相同的实现,python代码运行得更快。我已经读过python通常比ruby快,但这是一个预期的速度差异吗?
miller_rabin.rb
def miller_rabin(m,k)
t = (m-1)/2;
s = 1;
while(t%2==0)
t/=2
s+=1
end
for r in (0...k)
b = 0
b = rand(m) while b==0
prime = false
y = (b**t) % m
if(y ==1)
prime = true
end
for i in (0...s)
if y == (m-1)
prime = true
break
else
y = (y*y) % m
end
end
if not prime
return false
end
end
return true
end
count = 0
for j in (20..29000)
if(j%2==1 and miller_rabin(j,2))
count+=1
end
end
puts count
miller_rabin.py:
import math
import random
def miller_rabin(m, k):
s=1
t = (m-1)/2
while t%2 == 0:
t /= 2
s += 1
for r in range(0,k):
rand_num = random.randint(1,m-1)
y = pow(rand_num, t, m)
prime = False
if (y == 1):
prime = True
for i in range(0,s):
if (y == m-1):
prime = True
break
else:
y = (y*y)%m
if not prime:
return False
return True
count = 0
for j in range(20,29001):
if j%2==1 and miller_rabin(j,2):
count+=1
print count
当我在Windows Powershell中使用Measure-Command测量每个的执行时间时,我得到以下内容:
Python 2.7:
蜱虫:4874403
总毫秒数:487.4403
Ruby 1.9.3:
蜱虫:682232430
总毫秒数:68223.243
我很感激任何人都可以告诉我为什么他们之间存在如此巨大的差异
答案 0 :(得分:7)
在ruby中,您使用(a ** b) % c
来计算取幂的模数。在Python中,您使用了更有效的三元素pow
调用,其docstring明确指出:
有三个参数,相当于
(x**y) % z
,但可能更多 有效的(例如长期)。
你是否想要计算这种内置运营商对红宝石的缺乏是一个意见问题。一方面,如果红宝石没有提供一个,你可能会说它慢得多。另一方面,你并不是真的在算法上测试相同的东西,所以有人会说这种比较是不公平的。
快速的Google搜索显示了there are implementations对红宝石的模幂运算。
答案 1 :(得分:2)
我认为这些个人资料结果应该可以回答您的问题:
%self total self wait child calls name
96.81 43.05 43.05 0.00 0.00 17651 Fixnum#**
1.98 0.88 0.88 0.00 0.00 17584 Bignum#%
0.22 44.43 0.10 0.00 44.33 14490 Object#miller_rabin
0.11 0.05 0.05 0.00 0.00 32142 <Class::Range>#allocate
0.11 0.06 0.05 0.00 0.02 17658 Kernel#rand
0.08 44.47 0.04 0.00 44.43 32142 *Range#each
0.04 0.02 0.02 0.00 0.00 17658 Kernel#respond_to_missing?
0.00 44.47 0.00 0.00 44.47 1 Kernel#load
0.00 44.47 0.00 0.00 44.47 2 Global#[No method]
0.00 0.00 0.00 0.00 0.00 2 IO#write
0.00 0.00 0.00 0.00 0.00 1 Kernel#puts
0.00 0.00 0.00 0.00 0.00 1 IO#puts
0.00 0.00 0.00 0.00 0.00 2 IO#set_encoding
0.00 0.00 0.00 0.00 0.00 1 Fixnum#to_s
0.00 0.00 0.00 0.00 0.00 1 Module#method_added
与Python相比,Ruby的**
运算符看起来很慢。
看起来(b**t)
通常太大而无法在Fixnum
中修复,因此您使用的是Bignum
(或任意精度)算术,这要慢得多。