3

これまで、同じ関数を作成するためのさまざまなアプローチの速度をテストしている間、私はそのtime関数を使用してきました。一般に、さまざまな関数の相対速度をよく示しています(通常、約10万サイクル異なるため)。

factorialしかし、関数の最速のアプローチを見つけようとしている間、time欠けていました。これらの方法は、10k〜30kサイクルだけ異なるように見えるだけでなく、全体の時間もその約半分の量だけ異なります(これは予想されることです)。

3つのfactorial機能:

(defun factorial-recusion (n)   ; 1st      
  (if (equal n 1) 
      1
      (* n (factorial (- n 1)))))

(defun factorial-loop (n)   ; 2nd
  (let ((solution 1))
    (loop for x from n downto 2
       do (setf solution (* solution x))
       finally (return solution))))

(defun factorial-do (n)     ; 3rd
  (let ((solution 1))
    (do ((x n (1- x)))
    ((< x 2) (return solution))
      (setf solution (* solution x)))))

だから、私は2つの質問があると思います:

1.)どの方法factorialが最速である必要がありますか(実際にそうである場合)、そしてその理由は何ですか?

2.)一般的な方法でより高速な機能を自分で見つけた場合、それを行うための最良の方法は何ですか(何らかの理由で、LOCは速度の悪い指標だと思います)。おそらく、Lispバイトコードの逆アセンブルを表示する方法はありますか?それとも、もっと良い、もっと厳密な方法があるのでしょうか?

私は現在、Ubuntu 12.04x86-64でLinux3.2.0-26、SBCLを実行しています。

4

1 に答える 1

5

SBCLは「バイトコード」にコンパイルされません。ネイティブマシンコードにコンパイルされます。

を使用してLisp関数を分解できますDISASSEMBLE

階乗関数の速度は、数値がbignumの範囲に入ると、bignum算術乗算によって支配されます。

明確にするために、使用する反復構造(DOまたはLOOP)はそれほど重要ではありません。ほとんどの時間は、bignumの乗算に費やされます。再帰バージョンも大きな違いはありません。

これは典型的なベンチマークの問題です。多くの単純な数値ベンチマークは、いくつかの算術演算(bignumの乗算など)の実行時間によって支配されます。それらは、一般的な言語操作(さまざまなタイプの制御フローなど)の速度の違いをあまり測定しません。

高速なbignumライブラリを備えた低速のLispは、Lispで記述されたBignumコードを備えた最適化されたLispコンパイラよりも高速である可能性があります。

于 2012-07-21T12:26:12.727 に答える