Created
September 30, 2010 15:05
-
-
Save gintenlabo/604721 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// オレオレ性能測定 | |
#include "xor128.hpp" | |
// ローパスフィルタ | |
// 結果のランダムな性質を少し和らげて、より正確な処理ができるよう(気休めレベルですが) | |
struct LPF | |
{ | |
typedef double result_type; | |
explicit LPF( double x0 = 0 ) | |
: x_(x0), y_(x0) {} | |
result_type operator()( double x ) | |
{ | |
// カットオフ周波数に相当するもの | |
// 周期 Nc で繰り返されるものより波長の短い成分をカット | |
static int const Nc = 10; | |
// パラメータ設定 | |
static double const T_omega = 1.0 / Nc; | |
static double const kx = T_omega / ( 2.0 + T_omega ); | |
static double const ky = ( 2.0 - T_omega ) / ( 2.0 + T_omega ); | |
// 生成 | |
y_ = kx * ( x + x_ ) + ky * y_; | |
x_ = x; | |
return y_; | |
} | |
result_type get() const | |
{ | |
return y_; | |
} | |
private: | |
double x_, y_; | |
}; | |
// 乱数の初期状態を評価する | |
// 内部状態がほぼランダムになるまでに必要なステップ数を計算 | |
// 今回は平均しないので直接的に 1 の bit 数を数える | |
std::size_t evaluate( etude::Xor128& gen ) | |
{ | |
LPF lpf; | |
lpf( gen.get_state().count() ); | |
std::size_t const max_steps = 256; | |
for( std::size_t steps = 0; steps <= max_steps; ++steps ) | |
{ | |
// 判断基準。平滑化された 1 のビット数がこれ以上ならよし | |
// 2.0 は定常状態を LPF で平滑化したときの揺らぎの幅(標準偏差)の実測値 2.37 から | |
// それよりも適度に小さなキリのよい値として深く考えず採用。 | |
static double const norm = 64 - 2.0; | |
if( lpf.get() >= norm ) | |
{ | |
return steps; | |
} | |
gen(); | |
lpf( gen.get_state().count() ); | |
} | |
return -1; | |
} | |
// 乱数生成器を評価する | |
// 内部状態のばらつきを示した「スコア」が基準値を上回るまでにかかったステップ数を計算する | |
#include <cmath> | |
template<class F> | |
double evaluate_seed( F f ) | |
{ | |
// 内部状態の bit 数 | |
std::size_t const seed_bits = 32; | |
// std::time 等を考慮し、低い bit に対して重みを与える | |
double weight = 2.0; | |
double const rw = std::pow( weight, -1.0 / seed_bits ); | |
double sum_score = 0; | |
double sum_weight = 0; | |
// 種を 0…01 から順にシフトしていく | |
for( etude::Xor128::int_type seed = 1; seed != 0; seed <<= 1 ) | |
{ | |
etude::Xor128 gen( f(seed) ); | |
std::size_t score = evaluate(gen); | |
sum_score += weight * score; | |
sum_weight += weight; | |
weight *= rw; | |
} | |
// 平均 | |
return sum_score / sum_weight; | |
} | |
// 32bit 整数を左回りに n bit 回転させる | |
inline std::uint32_t rotate_left_32( std::uint32_t x, std::size_t n ) { | |
return ( x << n ) | ( x >> ( 32 - n ) ); | |
} | |
#include <iostream> | |
#include <boost/format.hpp> | |
#include <boost/progress.hpp> | |
#include <algorithm> | |
#include <vector> | |
#include <array> | |
#include <cfloat> | |
#include <cassert> | |
#include <boost/foreach.hpp> | |
// この辺でコメントによる解説は力尽きましたorz | |
int main() | |
{ | |
typedef etude::Xor128::int_type int_type; | |
typedef std::array<std::size_t, 4> array_type; | |
std::vector< std::pair< double, array_type > > results; | |
std::size_t const results_max = 100; | |
// if を減らすため results にダミーの要素を追加 | |
{ | |
results.reserve( results_max + 1 ); | |
array_type const dummy = {{ 32, 32, 32 }}; | |
for( std::size_t i = 0; i < results_max; ++i ) { | |
results.emplace_back( DBL_MAX, dummy ); | |
} | |
assert( results.size() == results_max ); | |
std::make_heap( results.begin(), results.end() ); | |
} | |
{ | |
std::size_t const int_bits = 32; | |
std::size_t const tested_cases = 32 * 32 * 32 * 32 - 31 * 31 * 31 * 31; | |
boost::progress_display show_progress( tested_cases, std::cerr ); | |
for( std::size_t a = 0; a < int_bits; ++a ) { | |
for( std::size_t b = a; b < int_bits; ++b ) { | |
for( std::size_t c = b; c < int_bits; ++c ) { | |
array_type nums = {{ 0, a, b, c }}; | |
do { | |
std::size_t const dx = nums[0], dy = nums[1], dz = nums[2], dw = nums[3]; | |
auto const f = [=]( int_type seed ) -> etude::Xor128 { | |
return etude::Xor128( | |
rotate_left_32( seed, dx ), rotate_left_32( seed, dy ), | |
rotate_left_32( seed, dz ), rotate_left_32( seed, dw ) | |
); | |
}; | |
double const score = evaluate_seed( f ); | |
// 今回の結果をヒープに追加して | |
results.emplace_back( score, nums ); | |
std::push_heap( results.begin(), results.end() ); | |
// 最大の要素を取り除く | |
std::pop_heap( results.begin(), results.end() ); | |
results.pop_back(); | |
++show_progress; | |
} | |
while( std::next_permutation( nums.begin(), nums.end() ) ); | |
} | |
} | |
} | |
} | |
std::cerr << std::endl; | |
// results の中身を sort | |
assert( results.size() == results_max ); | |
std::sort_heap( results.begin(), results.end() ); | |
// 表示 | |
std::cout << "dx dy dz dw : score\n\n"; | |
BOOST_FOREACH( auto const& x, results ) | |
{ | |
double const score = x.first; | |
auto const& params = x.second; | |
std::cout << boost::format("%1$02d %2$02d %3$02d %4$02d : %5%\n") | |
% params[0] % params[1] % params[2] % params[3] % score; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
dx dy dz dw : score | |
00 02 04 17 : 37.9233 | |
30 00 02 15 : 38.029 | |
28 30 00 13 : 38.2996 | |
01 18 00 19 : 38.8293 | |
00 17 31 18 : 38.8731 | |
14 31 13 00 : 38.8782 | |
15 00 14 01 : 38.9994 | |
30 00 10 28 : 39.0322 | |
00 02 04 03 : 39.0548 | |
02 04 14 00 : 39.0838 | |
16 12 26 00 : 39.0909 | |
00 02 12 30 : 39.1302 | |
00 28 10 16 : 39.2558 | |
04 00 14 20 : 39.2764 | |
07 27 00 25 : 39.3119 | |
09 27 00 02 : 39.3389 | |
12 00 05 30 : 39.3473 | |
00 13 12 28 : 39.3563 | |
00 18 23 25 : 39.3705 | |
00 14 07 21 : 39.3905 | |
04 17 16 00 : 39.4182 | |
14 00 15 18 : 39.4227 | |
07 25 30 00 : 39.433 | |
20 01 00 16 : 39.4388 | |
01 20 00 10 : 39.4633 | |
28 30 00 07 : 39.4697 | |
14 02 07 00 : 39.4852 | |
28 30 00 31 : 39.4981 | |
00 02 04 19 : 39.5 | |
02 25 00 12 : 39.5058 | |
29 31 01 00 : 39.511 | |
02 04 06 00 : 39.5206 | |
09 02 29 00 : 39.538 | |
13 15 17 00 : 39.5722 | |
22 18 00 06 : 39.5754 | |
00 20 25 18 : 39.5921 | |
12 05 00 03 : 39.5928 | |
30 00 02 09 : 39.6012 | |
30 00 02 01 : 39.6063 | |
00 19 31 09 : 39.6095 | |
00 23 30 10 : 39.6192 | |
02 04 00 06 : 39.6456 | |
00 02 04 11 : 39.6501 | |
17 00 10 12 : 39.6514 | |
00 14 01 18 : 39.6888 | |
31 13 00 17 : 39.6894 | |
09 29 28 00 : 39.6933 | |
18 00 14 07 : 39.7004 | |
00 02 25 20 : 39.712 | |
04 18 00 25 : 39.7184 | |
14 04 00 07 : 39.7249 | |
20 22 00 18 : 39.7384 | |
21 23 25 00 : 39.7416 | |
19 00 31 15 : 39.7584 | |
25 07 00 14 : 39.759 | |
30 10 29 00 : 39.7738 | |
30 00 23 18 : 39.7829 | |
02 12 00 19 : 39.8022 | |
00 02 30 04 : 39.8028 | |
10 00 28 03 : 39.8151 | |
17 00 15 21 : 39.8222 | |
28 30 00 15 : 39.8299 | |
07 29 25 00 : 39.8466 | |
00 14 28 21 : 39.8473 | |
00 07 12 17 : 39.8512 | |
30 00 28 02 : 39.857 | |
00 12 09 10 : 39.8582 | |
02 27 00 09 : 39.8608 | |
00 12 31 02 : 39.8615 | |
00 02 30 20 : 39.864 | |
14 00 05 07 : 39.8666 | |
28 14 29 00 : 39.8763 | |
18 00 25 07 : 39.8802 | |
01 13 00 03 : 39.8847 | |
22 15 29 00 : 39.8898 | |
02 04 00 22 : 39.8911 | |
30 00 02 17 : 39.8918 | |
00 14 18 12 : 39.8943 | |
02 17 00 06 : 39.9059 | |
12 00 31 03 : 39.9098 | |
07 25 00 13 : 39.9278 | |
28 25 24 00 : 39.9336 | |
07 00 27 30 : 39.9414 | |
13 00 12 22 : 39.9555 | |
20 02 06 00 : 39.9562 | |
10 20 00 27 : 39.9588 | |
13 01 00 04 : 39.9613 | |
00 14 15 18 : 39.9646 | |
22 00 18 17 : 39.9781 | |
00 18 25 06 : 39.9813 | |
18 00 19 04 : 39.9865 | |
22 12 21 00 : 39.9929 | |
18 00 14 04 : 39.9981 | |
00 29 10 17 : 40.0064 | |
00 02 04 05 : 40.011 | |
13 15 00 06 : 40.0122 | |
28 13 00 06 : 40.0142 | |
18 25 06 00 : 40.0264 | |
00 15 30 04 : 40.0271 | |
07 22 13 00 : 40.0284 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
dx dy dz dw : score | |
00 02 04 17 : 37.8872 | |
30 00 02 15 : 38.0415 | |
28 30 00 13 : 38.3594 | |
01 18 00 19 : 38.8072 | |
00 17 31 18 : 38.8542 | |
14 31 13 00 : 38.8915 | |
15 00 14 01 : 39.0206 | |
30 00 10 28 : 39.0264 | |
00 02 04 03 : 39.0433 | |
02 04 14 00 : 39.0517 | |
16 12 26 00 : 39.066 | |
00 02 12 30 : 39.1156 | |
00 28 10 16 : 39.2661 | |
04 00 14 20 : 39.2897 | |
09 27 00 02 : 39.2938 | |
00 14 07 21 : 39.3292 | |
07 27 00 25 : 39.3388 | |
00 13 12 28 : 39.3471 | |
12 00 05 30 : 39.3501 | |
00 18 23 25 : 39.3771 | |
04 17 16 00 : 39.4018 | |
07 25 30 00 : 39.4094 | |
14 00 15 18 : 39.4109 | |
20 01 00 16 : 39.4501 | |
02 25 00 12 : 39.4522 | |
28 30 00 07 : 39.46 | |
01 20 00 10 : 39.4622 | |
02 04 06 00 : 39.4718 | |
14 02 07 00 : 39.4979 | |
13 15 17 00 : 39.5152 | |
28 30 00 31 : 39.5225 | |
09 02 29 00 : 39.5274 | |
12 05 00 03 : 39.5307 | |
29 31 01 00 : 39.5339 | |
00 02 04 19 : 39.5691 | |
22 18 00 06 : 39.5851 | |
30 00 02 09 : 39.5899 | |
00 23 30 10 : 39.6059 | |
00 20 25 18 : 39.6075 | |
02 04 00 06 : 39.6152 | |
17 00 10 12 : 39.6183 | |
00 19 31 09 : 39.6237 | |
30 00 02 01 : 39.6332 | |
00 02 04 11 : 39.6408 | |
00 14 01 18 : 39.6673 | |
31 13 00 17 : 39.6745 | |
14 04 00 07 : 39.6866 | |
04 18 00 25 : 39.6885 | |
09 29 28 00 : 39.6897 | |
00 02 25 20 : 39.7006 | |
18 00 14 07 : 39.7115 | |
21 23 25 00 : 39.7767 | |
19 00 31 15 : 39.7833 | |
25 07 00 14 : 39.7867 | |
30 10 29 00 : 39.7884 | |
30 00 23 18 : 39.7976 | |
00 02 30 04 : 39.802 | |
17 00 15 21 : 39.8023 | |
20 22 00 18 : 39.8067 | |
14 00 05 07 : 39.8217 | |
10 00 28 03 : 39.8239 | |
02 12 00 19 : 39.824 | |
00 07 12 17 : 39.8406 | |
00 14 28 21 : 39.8469 | |
00 12 09 10 : 39.8473 | |
02 04 00 22 : 39.8542 | |
00 02 30 20 : 39.8576 | |
12 00 31 03 : 39.8635 | |
02 27 00 09 : 39.8637 | |
00 12 31 02 : 39.8676 | |
00 14 18 12 : 39.8725 | |
30 00 28 02 : 39.8738 | |
07 29 25 00 : 39.8756 | |
28 14 29 00 : 39.883 | |
01 13 00 03 : 39.8866 | |
28 30 00 15 : 39.8903 | |
22 15 29 00 : 39.8948 | |
07 25 00 13 : 39.895 | |
02 17 00 06 : 39.9041 | |
13 01 00 04 : 39.9043 | |
28 25 24 00 : 39.9108 | |
18 00 25 07 : 39.9286 | |
13 00 12 22 : 39.9393 | |
10 20 00 27 : 39.9489 | |
22 12 21 00 : 39.9649 | |
22 00 18 17 : 39.9672 | |
00 14 15 18 : 39.9684 | |
28 13 00 06 : 39.971 | |
30 00 02 17 : 39.9731 | |
07 00 27 30 : 39.9765 | |
13 15 00 06 : 39.9833 | |
00 29 10 17 : 39.9889 | |
18 17 00 22 : 40.0021 | |
00 18 25 06 : 40.005 | |
18 00 19 04 : 40.0059 | |
00 18 17 01 : 40.0098 | |
18 00 14 04 : 40.011 | |
03 00 13 20 : 40.0116 | |
18 25 06 00 : 40.0195 | |
10 00 20 14 : 40.0254 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef INCLUDED_ROTATE_LEFT_HPP_ | |
#define INCLUDED_ROTATE_LEFT_HPP_ | |
// ビット列を左に N ビットシフトして返す | |
#include <limits> // for std::numeric_limits | |
#include <boost/integer/integer_mask.hpp> | |
// ヘッダに分割したので一応名前空間に入れておこう | |
namespace etude | |
{ | |
// とりあえずテンプレート版。関数版も用意するかも | |
template<std::size_t N, class Int> | |
inline Int rotate_left( Int x ) | |
{ | |
typedef std::numeric_limits<Int> limits; | |
static const std::size_t Int_bits = limits::digits + ( limits::is_signed ? 1 : 0 ); | |
static const Int mask = static_cast<Int>( boost::low_bits_mask_t<N>::sig_bits ); | |
return ( x << N ) | ( mask & ( x >> ( Int_bits - N ) ) ); | |
} | |
} | |
#endif // #ifndef INCLUDED_ROTATE_LEFT_HPP_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef INCLUDED_XOR128_HPP_ | |
#define INCLUDED_XOR128_HPP_ | |
// xor128 乱数生成アルゴリズム | |
#include <cassert> | |
#include <boost/cstdint.hpp> | |
#include <bitset> | |
#include "rotate_left.hpp" | |
// ヘッダに分割したので一応名前空間に入れておこう | |
namespace etude | |
{ | |
struct Xor128 | |
{ | |
typedef boost::uint32_t result_type; | |
typedef boost::uint32_t int_type; | |
// min, max | |
static result_type min() { return 0; } | |
static result_type max() { return 0xFFFFFFFF; } | |
// デフォルト初期化 | |
Xor128() | |
: x(123456789), y(362436069), z(521288629), w(88675123) {} | |
// 種を元に乱数を初期化する | |
explicit Xor128( int_type seed ) | |
: x(123456789), y(362436069), z(521288629), w(88675123) | |
{ | |
x ^= seed; | |
y ^= rotate_left<17>(seed); | |
z ^= rotate_left<31>(seed); | |
w ^= rotate_left<18>(seed); | |
// あるいは | |
// x ^= rotate_left<14>(seed); | |
// y ^= rotate_left<31>(seed); | |
// z ^= rotate_left<13>(seed); | |
// w ^= seed; | |
} | |
// 全ての内部状態を指定して乱数を構築する | |
Xor128( int_type x_, int_type y_, int_type z_, int_type w_ ) | |
: x(x_), y(y_), z(z_), w(w_) | |
{ | |
assert( x != 0 || y != 0 || z != 0 || w != 0 ); | |
} | |
// 乱数生成 | |
result_type operator()() | |
{ | |
int_type const t = x ^ ( x << 11 ); | |
x = y; y = z; z = w; | |
w = ( w ^ ( w >> 19 ) ) ^ ( t ^ ( t >> 8 ) ); | |
return w; | |
} | |
// n 回読み飛ばす | |
void discard( std::size_t n ) | |
{ | |
for( std::size_t i = 0; i < n; ++i ){ (*this)(); } | |
} | |
// 比較 | |
friend bool operator==( Xor128 const& lhs, Xor128 const& rhs ) | |
{ | |
return lhs.x == rhs.x | |
&& lhs.y == rhs.y | |
&& lhs.z == rhs.z | |
&& lhs.w == rhs.w; | |
} | |
friend bool operator!=( Xor128 const& lhs, Xor128 const& rhs ) | |
{ | |
return !( lhs == rhs ); | |
} | |
// 内部状態を取得する | |
typedef std::bitset<128> state_type; | |
state_type get_state() const | |
{ | |
state_type state = x; | |
state <<= 32; | |
state |= state_type(y); | |
state <<= 32; | |
state |= state_type(z); | |
state <<= 32; | |
state |= state_type(w); | |
return state; | |
} | |
// state_type からの構築 | |
Xor128( state_type state ) | |
{ | |
state_type const mask = int_type(-1); | |
w = ( mask & state ).to_ulong(); | |
state >>= 32; | |
z = ( mask & state ).to_ulong(); | |
state >>= 32; | |
y = ( mask & state ).to_ulong(); | |
state >>= 32; | |
x = ( mask & state ).to_ulong(); | |
} | |
private: | |
int_type x, y, z, w; | |
}; | |
} | |
#endif // #ifndef INCLUDED_XOR128_HPP_ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
俺々性能チェック。説明面倒なので解読してください。