Ruby Maths函数记忆

时间:2009-10-07 05:01:02

标签: ruby math function memoization

我写了一些看起来像这样的代码:

def get(x, y)
   @cachedResults.set(x,y, Math.hypot(x, y)) if @cachedResults.get(x,y).nil?
   @cachedResults.get(x,y)
end

@cachedResults包含我编写的2D Array类(几分钟内),此函数的目的是确保我不必为任何给定的(x,y)调用Math.hypot两次。 [这可以使用对称和其他东西进一步优化,但无论如何]

所以我调用了函数,让它运行160000次;它跑了超过15秒。然后,为了看看它比非Memoized版本快多少,我将代码更改为:

def get(x, y)
   Math.hypot(x, y)
end

而且,令我惊讶的是,重新跑了仅需15秒。完全相同的时间。所以我的问题是,ruby中的数学函数自然是Memoized吗?如果是这样,ruby会在多大程度上回忆起来?

(如果没有,那你为什么认为我的结果一致?)

3 个答案:

答案 0 :(得分:4)

为你做160000次需要大约15秒吗?只需返回x即可在系统上进行基准测试;很可能是hypot操作(在C中实现)可以忽略解释器开销。

对于使用khell的memoized get方法的ruby 1.8.7,在get方法中调用函数,并在get方法中返回x,并进行100000次迭代:

peregrino:$ time ruby src/memoized_hypot.rb 

real    0m1.714s
user    0m1.436s
sys 0m0.080s
peregrino:$ time ruby src/plain_hypot.rb 

real    0m0.495s
user    0m0.364s
sys 0m0.060s
peregrino:$ time ruby src/empty_hypo.rb 

real    0m0.369s
user    0m0.220s
sys 0m0.068s

kheill的memoization在每次调用时都会创建一个字符串,这比在每次调用时调用C库的hypot函数要昂贵得多。

调用hypot和刚返回x之间的差异表明hypot仅占运行时的25%。这不是您应该优化的代码 - 而是尝试内联对库的调用,如果您可以而不是将其包装在另一个方法中。

peregrino:$ time ruby src/inline_hypot.rb 

real    0m0.365s
user    0m0.236s
sys 0m0.044s

100000.times{ |i| Math.hypot(i,6) }   

而不是

100000.times{ |i| foo.get(i,6) }   

其中foo是发布方法的对象。


这些时间都在上网本(华硕eeepc 900)上,这并不是非常快,所以它们比你的时间快得多,这有点奇怪。所以其他东西可能会支配你的结果。

答案 1 :(得分:3)

试试这个:

def initialize
  @cachedResults = {}
end

def get(x, y)
   @cachedResults["#{x}:#{y}"] ||= Math.hypot(x, y)
end

答案 2 :(得分:1)

在这种情况下,我不希望这里的记忆会改善很多

Math.hypot 做的只是sqrt(x**2 + y**2)。它不是对已经计算的值的递归调用。