LoginSignup
3
4

More than 5 years have passed since last update.

テンプレートメタ疑似乱数生成器 (雑)

Last updated at Posted at 2015-05-27

概略

C++ で std::array<int, N>N に対して randomized test をやりたい、というめんどくさい欲求を抱いてしまったので、この論文丸パkさんこうに実装してみました1

コード

自分は C++ のテンプレートはあまり詳しくないため、オボロゲに理解はできるけど、突っ込んだ説明は無理ゲーなので、解説は元論文をあたるか、お近くのテンプレートメタプロ魔王に聞いてみてください。丸投げメソッド。

// tempra.hpp
#pragma once

#include <cstdint>
#include <climits>

template<uint32_t x, uint32_t y, uint32_t z, uint32_t w>
struct meta_xor128 {
    static const uint32_t x_ = x;
    static const uint32_t y_ = y;
    static const uint32_t z_ = z;
    static const uint32_t w_ = w;
    static const uint32_t value = w;
};

template<typename E>
struct eval {
    typedef E type;
};

template<typename E>
struct init {
    typedef typename eval<E>::type type;
    static const uint32_t value = type::value;
};
template<uint32_t x, uint32_t y, uint32_t z, uint32_t w>
struct init<meta_xor128<x,y,z,w>> {
    typedef typename eval<meta_xor128<x,y,z,w>>::type type;
    static const uint32_t value = type::value;
};

template<uint32_t x, uint32_t y, uint32_t z, uint32_t w>
struct eval<meta_xor128<x,y,z,w>> {
    #define t (x ^ (x << 11 ))
    static const uint32_t value = (w ^ (w>>19)) ^ (t ^ (t >> 8));
    typedef meta_xor128<y, z, w, (w ^ (w>>19)) ^ (t ^ (t >> 8))> type;
    #undef t
};

template<typename Engine>
struct Random {
    typedef typename init<Engine>::type type;
    static const decltype(type::value) value = type::value;
};

template <typename R>
struct Next {
    typedef typename eval<R>::type type;
    static const decltype(type::value) value = type::value;
};


constexpr char inits[] = __TIME__;
constexpr uint32_t DEFAULT_SEED = 
(inits[0]-'0')*100000+(inits[1]-'0')*10000 +
(inits[3]-'0')*1000+(inits[4]-'0')*100+
(inits[6]-'0')*10+inits[7]-'0';

typedef typename Random<meta_xor128<DEFAULT_SEED, DEFAULT_SEED+13, DEFAULT_SEED+34, DEFAULT_SEED+89>>::type META_PRNG;

使用例

// main.cpp
#include <array>
#include <iostream>
#include "tempra.hpp"

template<unsigned n, typename R>
struct print_randoms {
    static void print() {
        typedef typename Next<R>::type RND;
        std::cout << RND::value << std::endl;
        print_randoms<n-1, RND>::print();
    };
};

template<typename R>
struct print_randoms<0, R> {
    static void print() {
        std::cout << Next<R>::value << std::endl;
    };
};

template<unsigned n, typename R>
struct make_random_arity_array {
    static void print() {
        typedef typename Next<R>::type RND;
        std::array<int, RND::value % 65536> a;
        std::cout << "a is std::array<int, " << a.size() << ">" << std::endl;
        make_random_arity_array<n-1, RND>::print();
    };
};

template<typename R>
struct make_random_arity_array<0, R> {
    static void print() {
        typedef typename Next<R>::type RND;
        std::array<int, RND::value % 65536> a;
        std::cout << "a is std::array<int, " << a.size() << ">" << std::endl;
    };
};

int main(int ac, char** av) {
    print_randoms<10, META_PRNG>::print();
    make_random_arity_array<10, META_PRNG>::print();
    return 0;
}
$ gcc -std=c++11 main.cpp -lstdc++ -o tempra-test
$ ./tempra-test
172628
374345336
219481
2355161479
2573593181
265295047
352538101
2661593603
673551496
2816265063
2831111820
a is std::array<int, 41556>
a is std::array<int, 3704>
a is std::array<int, 22873>
a is std::array<int, 59783>
a is std::array<int, 59997>
a is std::array<int, 5319>
a is std::array<int, 19957>
a is std::array<int, 45571>
a is std::array<int, 38024>
a is std::array<int, 52071>
a is std::array<int, 22156>

注意

疑似乱数列はコンパイル時に定まっているので (ほぼ by definition)、同じバイナリを何回も実行して「ちっともランダムじゃないじゃないか!」とか怒らないようにしましょう。


  1. しかしこれ、SPLST'13 とかいう学会で発表実績があるらしいのに、DBLP にもひっかからないし Google Scholor の Bibtex にも情報量ゼロなのはなんなんだ。 

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4