每个都比在Ruby中慢吗?

时间:2014-10-09 08:30:17

标签: ruby while-loop each benchmarking

以下两个函数,用于检查数字是否为素数:

def prime1?(prime_candidate)
  return true if [1, 2].include? prime_candidate
  range = 2.upto(Math.sqrt(prime_candidate).ceil).to_a
  i = 0
  while i < range.count
    return false if prime_candidate % range[i] == 0
    range = range.reject { |j| j % range[i] == 0 }
  end
  true
end

def prime2?(prime_candidate)
  return true if [1, 2].include? prime_candidate
  range = 2.upto(Math.sqrt(prime_candidate).ceil).to_a
  range.each do |i|
    return false if prime_candidate % i == 0
    range = range.reject { |j| j % i == 0 }
  end
  true
end
当使用非常大的素数(5915587277)进行测试时,

产生以下的benchamrking结果:

              user     system      total        real
prime1:    2.500000   0.010000   2.510000 (  2.499585)
prime2:   20.700000   0.030000  20.730000 ( 20.717267)

为什么?是因为在第二个函数range中没有被reject修改,所以each正在迭代原始的长range

1 个答案:

答案 0 :(得分:2)

当你执行range=range.reject {..}时,你不会修改父范围(你不应该这样做,因为它会弄乱迭代 - 你需要reject!才能做到这一点)而是构造一个临时数组,只在迭代结束时分配给父范围变量。

each中的prime2次迭代在整个原始范围内运行,而不是缩短,在循环结束之前,只在块中存在。

while版本修改了原始数组,因此更快(顺便说一句,你意识到我仍然为零,而range.count在那条状中改变(减少),而拒绝再次遍历整个数组 - - 即使是可能无法拒绝任何更多非主要内容的开头。

如果您改进代码的逻辑,您将获得更快的结果。这种数组操作代价很高,为此,您甚至不需要数组:

def prime3?(prime_candidate)
  return false if prime_candidate==1
  return true if prime_candidate==2
  range = 2..(Math.sqrt(prime_candidate).ceil)
  range.all? {|x|  prime_candidate % x !=0 }
end #about 300× times as fast for your example as prime1? on my PC