#概略
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)、同じバイナリを何回も実行して「ちっともランダムじゃないじゃないか!」とか怒らないようにしましょう。
-
しかしこれ、SPLST'13 とかいう学会で発表実績があるらしいのに、DBLP にもひっかからないし Google Scholor の Bibtex にも情報量ゼロなのはなんなんだ。 ↩