using System;
using System.Collections.Generic;
class App
{
static public void Main(string[] args)
{
const int N = 6;
// 素朴にループで
Console.WriteLine(Fact1(N));
// 素朴に再帰で
Console.WriteLine(Fact2(N));
// コールスタックを自前で用意して再帰っぽく
Console.WriteLine(Fact3(N));
}
// 素朴にループ
static int Fact1(int n)
{
int prod = 1;
for (int i = 0; i < n; i++)
{
prod *= (i + 1);
}
return prod;
}
// 素朴に再帰
static int Fact2(int n)
{
if (n == 0) return 1;
return n * Fact2(n - 1);
}
// コールスタックに積まれる情報
class Frame
{
public int Arg { get; set; }
public int Ret { get; set; }
public Frame(int arg) { Arg = arg; }
}
// C#が提供するコールスタックを使わず
// スタックを自前で用意
static int Fact3(int n)
{
// なんちゃってコールスタック
Stack<Frame> frames = new Stack<Frame>();
Frame f = new Frame(n);
while(true)
{
if (f.Arg == 0)
{
// 再帰の出口
f.Ret = 1;
break;
}
else
{
// 再帰呼び出し
frames.Push(f);
f = new Frame(f.Arg - 1);
}
}
// 残りの掛け算
while (0 < frames.Count)
{
Frame peek = frames.Peek();
peek.Ret = f.Ret * peek.Arg;
f = frames.Pop();
}
return f.Ret;
}
}
dXNpbmcgU3lzdGVtOwp1c2luZyBTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYzsKCmNsYXNzIEFwcAp7CiAgc3RhdGljIHB1YmxpYyB2b2lkIE1haW4oc3RyaW5nW10gYXJncykKICB7CiAgICBjb25zdCBpbnQgTiA9IDY7CgogICAgLy8g57Sg5py044Gr44Or44O844OX44GnCiAgICBDb25zb2xlLldyaXRlTGluZShGYWN0MShOKSk7CgogICAgLy8g57Sg5py044Gr5YaN5biw44GnCiAgICBDb25zb2xlLldyaXRlTGluZShGYWN0MihOKSk7CgogICAgLy8g44Kz44O844Or44K544K/44OD44Kv44KS6Ieq5YmN44Gn55So5oSP44GX44Gm5YaN5biw44Gj44G944GPCiAgICBDb25zb2xlLldyaXRlTGluZShGYWN0MyhOKSk7CiAgfQoKICAvLyDntKDmnLTjgavjg6vjg7zjg5cKICBzdGF0aWMgaW50IEZhY3QxKGludCBuKQogIHsKICAgIGludCBwcm9kID0gMTsKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgbjsgaSsrKQogICAgewogICAgICBwcm9kICo9IChpICsgMSk7CiAgICB9CiAgICByZXR1cm4gcHJvZDsKICB9CgogIC8vIOe0oOactOOBq+WGjeW4sAogIHN0YXRpYyBpbnQgRmFjdDIoaW50IG4pCiAgewogICAgaWYgKG4gPT0gMCkgcmV0dXJuIDE7CiAgICByZXR1cm4gbiAqIEZhY3QyKG4gLSAxKTsKICB9CgogIC8vIOOCs+ODvOODq+OCueOCv+ODg+OCr+OBq+epjeOBvuOCjOOCi+aDheWgsQogIGNsYXNzIEZyYW1lCiAgewogICAgcHVibGljIGludCBBcmcgeyBnZXQ7IHNldDsgfQogICAgcHVibGljIGludCBSZXQgeyBnZXQ7IHNldDsgfQogICAgcHVibGljIEZyYW1lKGludCBhcmcpIHsgQXJnID0gYXJnOyB9CiAgfQoKICAvLyBDI+OBjOaPkOS+m+OBmeOCi+OCs+ODvOODq+OCueOCv+ODg+OCr+OCkuS9v+OCj+OBmgogIC8vIOOCueOCv+ODg+OCr+OCkuiHquWJjeOBp+eUqOaEjwogIHN0YXRpYyBpbnQgRmFjdDMoaW50IG4pCiAgewogICAgLy8g44Gq44KT44Gh44KD44Gj44Gm44Kz44O844Or44K544K/44OD44KvCiAgICBTdGFjazxGcmFtZT4gZnJhbWVzID0gbmV3IFN0YWNrPEZyYW1lPigpOwoKICAgIEZyYW1lIGYgPSBuZXcgRnJhbWUobik7CiAgICB3aGlsZSh0cnVlKQogICAgewogICAgICBpZiAoZi5BcmcgPT0gMCkKICAgICAgewogICAgICAgIC8vIOWGjeW4sOOBruWHuuWPowogICAgICAgIGYuUmV0ID0gMTsKICAgICAgICBicmVhazsKICAgICAgfQogICAgICBlbHNlCiAgICAgIHsKICAgICAgICAvLyDlho3luLDlkbzjgbPlh7rjgZcKICAgICAgICBmcmFtZXMuUHVzaChmKTsKICAgICAgICBmID0gbmV3IEZyYW1lKGYuQXJnIC0gMSk7CiAgICAgIH0KICAgIH0KCiAgICAvLyDmrovjgorjga7mjpvjgZHnrpcKICAgIHdoaWxlICgwIDwgZnJhbWVzLkNvdW50KQogICAgewogICAgICBGcmFtZSBwZWVrID0gZnJhbWVzLlBlZWsoKTsKICAgICAgcGVlay5SZXQgPSBmLlJldCAqIHBlZWsuQXJnOwogICAgICBmID0gZnJhbWVzLlBvcCgpOwogICAgfQogICAgcmV0dXJuIGYuUmV0OwogIH0KfQo=