Rokiのチラ裏

学生による学習のログ

Template non-type arguments (Variadic templates) によるコンパイル時乱数生成

Variadic templates でコンパイル時に乱数を生成してみた。現段階ではエンジンとして linear congruential, Xorshift, mersenne twister を、Discrete Uniform Distribution として uniform_int_distribution を実装してみた。ただし Template non-type arguments に対して実数を扱わせる事はできないので*1、そのようなものに対する Discrete Uniform Distribution は linear congruential で用いられる方法を流用している*2また、discard 的なものは未実装であるがこれも追々実装予定。実装した。

github.com

一応こんな感じに書ける。

make_random_sequenceという命名がなんだか微妙だが、make_index_sequenceに則って取り敢えずそうしている。それぞれ乱数エンジンの型は、resultnext_type型とdiscart_type型を持っており、resultが現在の擬似乱数の生成された値、next_typeが次の擬似乱数を生成する型、discart_typeが指定された回数分内部状態が進んだ擬似乱数を生成する型となっている。
尚、パラメータパックの保持する値に対してランダムアクセスを行おうとすると、再帰によって値を1つ1つ捨てる他がないので、これが線形となってしまってとても時間がかかる。これを極力避けた。また、C++1z からテンプレート引数型にautoを記述する事ができるようになったが、これを再帰中に多様すると型推論の負荷が強く、手元のコンパイラ(GCC 7.1.0)では有限時間内にコンパイルが完了せず abort trap で死んだので、 mersenne twister の実装などでは特に型を明示するようにしている。

以下は、srook::anypack<>::random::mersenne_twister のテストコード。実装はこれをパスする。

*1:N4660 [temp.arg.nontype]. ただし参照を除く

*2:std::ratio を使って追々実装するかもしれない