web-dev-qa-db-ja.com

LISPで1000階乗の計算が非常に高速なのはなぜですか(正しい結果が表示されます)。

LISPで階乗の単純な計算を実装しようとしました。

_(defun factorial (n)
  (if (equal n 1)
    1
    (* n (factorial (- n 1)))))
_

このコードは、予想どおり、少数(<10)で機能します。しかし、私はそれがはるかに高い数値(たとえば1000)でも機能し、結果がほぼ瞬時に計算されることに非常に驚いています。

一方、C++では、次のコードはfactorial(1000)の0を取得します。

_long long unsigned factorial(int n)
{
    if(n == 1) return 1;
    return n * factorial(n-1);
}
_

なぜLISPでの計算は非常に高速で、数値はどのようにメモリに格納されるのですか?

3
Hawklike

一般的なLISPは(理論的には)整数に制限を課しません(たとえばPythonなど)。整数のストレージは、大きな整数を表すために必要に応じて自動的に割り当てられます。反対側では、C++ネイティブ整数(例:intタイプ)は、固定サイズのメモリに格納されます。現在のほとんどのプラットフォームでは、サイズは通常1〜8バイトです。

C++アプローチの利点は、整数計算が非常に高速なプロセッサ命令(Common LISPとは異なり)に直接コンパイルできるため、整数計算が非常に高速になることです。ただし、欠点は、計算された値が大きすぎてC++のネイティブ整数型変数に収まらない場合、オーバーフローが発生することです。結果の値は数学的に正しくありません。

factorial(1000)は非常に大きな数値であるため、通常はネイティブ整数に収まりません。 Boost multi-precision library で提案されているような(非標準の)高レベルの可変サイズのC++整数型を使用すると、数学的に正しい結果を得ることができます。これを使用すると、factorial(1000)の計算もC++で非常に迅速に実行できます(数学的にも正確です)。

1