1

私は次のようなコードを書きました:

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配列クラスが含まれている場合(数分で)、この関数の目的は、任意の(x、y)に対してMath.hypotを2回呼び出す必要がないことを確認することです。[これは、対称性などを使用してさらに最適化できますが、何でも]

そこで、関数を呼び出して、160000回実行させました。15秒強で実行されました。次に、メモ化されていないバージョンよりもどれだけ高速かを確認するために、コードを次のように変更しました。

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

そして、驚いたことに、再び実行するのに15秒強かかりました。まったく同じ時間。だから私の質問は、ルビーの数学関数は自然にメモ化されているのですか?そして、もしそうなら、ルビーはどの程度メモ化されていますか?

(そうでない場合、なぜ私はこの結果を一貫して得ていると思いますか?)

4

3 に答える 3

4

あなたのために160000回何かをするのに約15秒かかりますか?xを返すだけでシステムにベンチマークします。(Cで実装された)hypot操作はインタープリターのオーバーヘッドよりも無視できる可能性があります。

khellのメモ化されたgetメソッドを使用するruby1.8.7の場合、getメソッド内で関数を呼び出し、getメソッド内でxを返すだけで、100000回の反復が行われます。

peregrino:$ time ruby​​ src / memoized_hypot.rb

実数0分1.714秒
ユーザー0m1.436s
sys 0m0.080s
peregrino:$ time ruby​​ src / plain_hypot.rb

実数0分0.495秒
ユーザー0m0.364s
sys 0m0.060s
peregrino:$ time ruby​​ src / empty_hypo.rb

実数0m0.369s
ユーザー0m0.220s
sys 0m0.068s

kheillのメモ化では、すべての呼び出しで文字列が作成されます。これは、すべての呼び出しでCライブラリのhypot関数を呼び出すよりもはるかにコストがかかります。

呼び出し側のhypotと単にxを返すことの違いは、hypotが実行時間の25%しか寄与していないことを示しています。最適化する必要のあるコードではありません。代わりに、別のメソッドでラップするのではなく、可能であればライブラリへの呼び出しをインライン化してみてください。

peregrino:$ time ruby​​ src / inline_hypot.rb

実数0m0.365s
ユーザー0m0.236s
sys 0m0.044s

これは

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

それよりも

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

ここで、fooはメソッドが投稿されたオブジェクトです。


これらの時間は、それほど高速ではないネットブック(Asus eeepc 900)にあったので、あなたの時間よりもはるかに速いのは少し奇妙です。したがって、他の何かが結果を支配している可能性があります。

于 2009-10-07T08:43:59.397 に答える
3

これを試して:

def initialize
  @cachedResults = {}
end

def get(x, y)
   @cachedResults["#{x}:#{y}"] ||= Math.hypot(x, y)
end
于 2009-10-07T05:40:36.700 に答える
1

この場合、ここでの暗記が大幅に改善されるとは思いません。

Math.hypotが行うことはただsqrt(x**2 + y**2). すでに計算された値への再帰呼び出しではありません。

于 2009-10-07T05:26:24.813 に答える