作者: 機械伯爵
日時: 2009/4/27(06:04)
凡例:
	n	階乗にする数
	fn	n!の値
	fact	階乗を返す関数


■ループを用いた方法

特長:
	直感的、シンプル

難点:
	グローバル変数の再代入。ただし、グローバル変数を使うこと自体は、
	変数管理の厳しいPascalであればさほど気にする必要は無いのかもしれ
	ない(関数化は可能だが、あまり意味はなさそうだ)

<repeat-untilループを使った例>

program factorial(output);
var n, fn: integer;
begin
  n := 10;
  fn := 1;
  repeat
    fn := fn * n;
    n := n - 1;
  until n < 2;
  writeln(fn);
end.

コメント:repeat文によるループ。次掲のgoto文によるループと基本的には同じ。
	単純だが、階乗のような単純構造のプログラムは、この形が案外わかり
	やすいのかもしれない。



<goto文を使った原始的なループ>

program factorial(output);
label 100;
var n, fn: integer;
begin
  n := 10;
  fn := 1;
  100:
    fn := fn * n;
    n := n - 1;
  if n > 1 then goto 100;
  writeln(fn);
end.

コメント:わざわざgotoループを使っているが、Pascalであればrepeat文か
	while文を使うのが自然。構造化機能の無いBASICからの転向者(現代で
	はそれもどれくらい居るものなのか?)のための説明コード、といった
	ところか。



<whileループを使った例>

program factorial(output);
var n, fn: integer;
begin
  n := 10;
  fn := 1;
  while n > 1 do
    begin
      fn := fn * n;
      n := n - 1;
    end;
  writeln(fn);
end.

コメント:whileループを使った例だが、階乗計算のような単純なものでれば、
	repeatのほうが見やすい。



<forループを使った例>

program factorial(output);
var t, n: integer;
begin
  n := 1;
  for t:=1 to 10 do n := n * t;
  writeln(n);
end.

コメント:ステップ増加式のfor文を使った例。カウンタが素直に使えて見やす
	い。



■再帰関数を使った例
特長:
	再帰関数を用いる
	変数がやや少なくて済む

難点:
	際立ったメリットが無いのに書きづらく、わかりづらい

<単純再帰>

program factorial(output);
function fact(n: integer):integer;
begin
  if n < 2
    then fact := 1
    else fact := fact(n - 1) * n
end;
begin
  writeln(fact(10));
end.

コメント:再帰の基本形


<末尾再帰>
program factorial(output);
function fact(n, t: integer):integer;
begin
  if n < 2
    then fact := t
    else fact := fact(n - 1, t * n)
end;
begin
  writeln(fact(10, 1));
end.

コメント:末尾再帰の基本形。本来、末尾再帰は最適化されてgotoループになる
	ことを望むためのものかもしれないが、最適化されない上、goto文が別
	に存在するPascalで書く必要は(勉強や遊び以外では)ほとんどない。



■型とリストを使った例

特長:
	Pascalの特長である型を駆使
	マジカルナンバーの除去
	プログラムの修正がしやすい
	カウンタの範囲設定により、無限ループを監視できる

難点:
	Pascalを知らない人は首をかしげる

<型とリストを使用した例>

program factorial(output);
const
  n = 10;
type
  length = 1..n;
var
  s : array[length] of integer;
  c : length;
begin
  s[1] := 1;
  c := 1;
  repeat
    c := c + 1;
    s[c] := s[c - 1] * c;
  until c = n;
  writeln(s[n]);
end.

コメント:最後に、Pascalの代名詞とも言える範囲型を導入してみた。確かにコ
	ンパイルが必要な言語では、型によるセーフティーネットの安心感は大
	きい。