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での計算は非常に高速で、数値はどのようにメモリに格納されるのですか?
一般的なLISPは(理論的には)整数に制限を課しません(たとえばPythonなど)。整数のストレージは、大きな整数を表すために必要に応じて自動的に割り当てられます。反対側では、C++ネイティブ整数(例:intタイプ)は、固定サイズのメモリに格納されます。現在のほとんどのプラットフォームでは、サイズは通常1〜8バイトです。
C++アプローチの利点は、整数計算が非常に高速なプロセッサ命令(Common LISPとは異なり)に直接コンパイルできるため、整数計算が非常に高速になることです。ただし、欠点は、計算された値が大きすぎてC++のネイティブ整数型変数に収まらない場合、オーバーフローが発生することです。結果の値は数学的に正しくありません。
factorial(1000)
は非常に大きな数値であるため、通常はネイティブ整数に収まりません。 Boost multi-precision library で提案されているような(非標準の)高レベルの可変サイズのC++整数型を使用すると、数学的に正しい結果を得ることができます。これを使用すると、factorial(1000)
の計算もC++で非常に迅速に実行できます(数学的にも正確です)。