Collatz予想
キミならどう書く 2.0 - ROUND 2 -
http://ll.jus.or.jp/2006/blog/doukaku2
Collatz予想のステップ数を求めるコードを書こうかと思いましたが、私の気になる言語Scheme, Io, Ocamlは既に先を越されているようで無念至極、諦めかけたところC++で記述してる例を見かけました。
C++はLLではないとの見方が優勢なのだと思っていましたが、特に誰も気にしてないようなので、私もこっそりC++で書いてみることにします。
(ロクにC++使ったことも無いくせに・・・)
ただし、こちらは以下のルールを勝手に設けてみました。
要するにtemplateで解を得ましょうという話です。
まず、ステップ数の計算は以下のようなtemplate展開から求められます
#includetemplate struct _f{ enum{value = 0}; }; /* even */ template struct _f<0, n>{ enum{value = 1 + _f<(n / 2) % 2, n / 2>::value}; }; /* odd */ template struct _f<1, n>{ enum{value = 1 + _f<(n * 3 + 1) % 2, n * 3 + 1>::value}; }; template <> struct _f<1, 1>{ enum{value = 1}; }; template struct f{ enum{value = _f ::value}; }; int main(){ std::cout << f<3>::value << std::endl; return 0; }
パラメータ「3」を与えている上記のコードをコンパイル、実行してみると、ステップ数である「8」が出力されます。
では、お題は1から100までのなかから、最大のステップ数となる数を求めるとのことなので、そのように展開されるtemplateを定義してみましょう。
#includeconst int max = 100; template struct _f{ enum{value = 0}; }; /* even */ template struct _f<0, n>{ enum{value = 1 + _f<(n / 2) % 2, n / 2>::value}; }; /* odd */ template struct _f<1, n>{ enum{value = 1 + _f<(n * 3 + 1) % 2, n * 3 + 1>::value}; }; template <> struct _f<1, 1>{ enum{value = 1}; }; template struct f{ enum{value = _f ::value}; }; template struct _Compare{ enum{value = 0}; enum{index = 0}; }; template struct _Compare<1, x, y, xi, yi>{ enum{value = x}; enum{index = xi}; }; template struct _Compare<0, x, y, xi, yi>{ enum{value = y}; enum{index = yi}; }; template struct Compare{ enum{value = _Compare = y, x, y, xi, yi>::value}; enum{index = _Compare = y, x, y, xi, yi>::index}; }; template struct Loop{ enum{value = 0}; enum{index = 0}; }; /* last */ template struct Loop<1, current, max>{ enum{value = f ::value}; enum{index = current}; }; template struct Loop<0, current, max>{ enum{value = Compare< f ::value, Loop ::value, current, Loop ::index >::value }; enum{index = Compare< f ::value, Loop ::value, current, Loop ::index >::index }; }; /* main loop */ template struct h{ enum{value = Loop<0, 1, max>::index}; }; int main(){ std::cout << h ::value << std::endl; std::cout << f< h ::value >::value << std::endl; return 0; }
このコードをコンパイル、実行した結果、「97」と「119」が出力されるはずです。
前者が解で、後者はそのステップ数となります。
上記のコードは無駄が散見されるものですが、サンプルということでお目汚しのほどご勘弁を。