2


1

fがある値を別の値に変換するようにしてから、変換をn回繰り返す関数を書いています。

私は二つの異なる方法を考え出しました:

  • 1つは文字通り関数をn回適用する明白な方法です、従って* repeat(f、4) x→f(f(f(f(f))))*を意味します

  • もう1つの方法は、力を与えるための高速な方法からヒントを得たものです。これは、nが偶数である場合は常に、問題を半分の大きさの2つの問題に分割することを意味します。 だから* repeat(f、4) x→g(g(x))を意味します*ここで* g(x)= f(f(x))*

最初は、2番目の方法では効率はそれほど向上しないと思いました。 一日の終わりには、まだf n回適用する必要がありますよね。 上記の例では、* g はそれ以上の単純化なしに f o f *に変換されます。

しかし、私がメソッドを試したとき、後者のメソッドは早く目立ちました。

;; 2つの関数の合成を計算します(定義(f g)(lambda(x)(f(g x))))。

;;識別関数(define(id x)x)

;;素朴な方法で関数の適用を繰り返す)

;;関数の適用を繰り返し、nを征服するように分割する(define(repeat2 f n)(define iter f k acc)(cond((= k 0)acc)) k)(iter(f fを構成)(/ k 2)acc))(else(it f( -  k 1)(f accを構成)))))(it f n id))

;;テストに使用される増分関数(define(inc x)(x 1))

実際、((repeat2 inc 1000000)0)*は((repeat1 inc 1000000)0)*よりはるかに高速でした。 私の質問は、2番目の方法が1番目の方法よりも効率的だったという点です。 同じ関数オブジェクトを再利用すると、記憶域が節約され、新しいオブジェクトの作成にかかる時間が短縮されますか

結局のところ、アプリケーションをn回繰り返す必要があります。つまり、* x→((x 1)1)を自動的に x→(x 2)*に減らすことはできません。

私はDrScheme 4.2.1を実行しています。

どうもありがとうございました。

2 Answer


3


どちらのバージョンでも同じ回数の `inc`を呼び出すのは正しいことですが、コードにはそれよりも多くのオーバーヘッドがあります。 具体的には、最初のバージョンではN個のクロージャが作成されますが、2番目のバージョンではlog(N)個のクロージャのみが作成されます。

これを詳細に見るために使用できるものが3つあります。

  1. 速度を測定するには、DrSchemeの `time`特殊形式を使用してください。 計算にかかる時間に加えて、GCにどのくらいの時間がかかったかもわかります。 あなたは、最初のバージョンがGC作業をしているのに対し、2番目のバージョンはしていないことがわかります。 (まあ、それはしますが、それは非常に小さいので、おそらく表示されないでしょう。)

  2. あなたの `inc`関数はほんの少ししかしていないので、あなたはループのオーバーヘッドだけを測定しています。 たとえば、私がこの悪いバージョンを使うとき:

(define(slow-inc x)(define(plus1 x)(/(if(<(random 10)5)(*(x 1)2)(2)(* x 2)2))2))2))) -   - (plus1 (プラス1(プラス1×))2))

この2つの用途の違いは、約11から1.6に低下します。 . 最後に、このバージョンを試してみてください。

(define(repeat 3 f n)(λ(x)(define iter n x)(if(zero? n)x(iter(sub 1 n)(f x))))(iter n x)))

それはどんな構成もしません、そしてそれはあなたの2番目のバージョンとほぼ同じ速度で動作します。


1


第一の方法は本質的に関数をn回適用し、従ってそれはO(n)である。 しかし、2番目の方法は実際には関数をn回適用していません。 repeat2が呼ばれるたびに、nが偶数であるときはいつでも、それはnを2で割ります。 したがって、多くの場合、問題のサイズは単に1ずつ減少するのではなく、半分になります。 これはO(log(n))の全体的なランタイムを与えます。

https://stackoverflow.com/users/46642/martinho-fernandes[Martinho Fernandez]が示唆しているように、 https://stackoverflow.com/users/46642/martinho-fernandes[2乗による指数関数化]のwikipediaの記事は非常に明確に説明しています。