/**
 *  @file XorShiftRand.h
 *  @note:
 *  -   xor shift 関係のサイト
        http://www.jstatsoft.org/v08/i14/paper
 *      http://www.iro.umontreal.ca/~lecuyer/myftp/papers/xorshift.pdf
 *      よい乱数悪い乱数 http://www001.upp.so-net.ne.jp/isaku/rand.html
 *      2ch 擬似乱数2   http://pc12.2ch.net/test/read.cgi/tech/1192628099/ (42, 55, 76)
 *
 *  -   とりあえずtemplateにして特殊化で 32,64,96,128,160,192,256の周期を指定にしている.
 *      当初の目論見ではinit(),get()をinline化させないような記述のためだったが
 *      特殊化クラスのメンバーの記述がよくわからず結局class内に実装.
 *  -   なので普通に XorShiftRand32 のように書いたほうがよかったかも. (が面倒なんでこのまま)
 */
#ifndef XORSHIFTRAND_H
#define XORSHIFTRAND_H

/// intが32ビットかを確認.
typedef char check_int_is_32bits[ sizeof(int) == 4 ? 1/*OK*/ : -1/*NG*/ ];


/// 32bit符号無整数を返す XOR SHIFT 法の乱数.   C=周期のビット数.
template<unsigned C>
class XorShiftRand {    // この定義は実体化することはない(したらエラー).
    typedef char check[(C==32||C==64||C==96||C==128||C==160||C==192||C==256) ? 1/*ok*/ : -1/*ng*/];
};



#ifdef XORSHIFTRAND_TEST
/// 周期2**32 - 1のxor shift 乱数. (paper文中の奴)
template<>
class XorShiftRand<32> {
    unsigned    seed_;
public:
    XorShiftRand(unsigned s=0) { init(s); }

    void init(unsigned s) {
        seed_ = s ? s : 2463534242U;
    }

    unsigned get() {
        unsigned x  = seed_;
        x ^= (x << 13);
        x ^= (x >> 17);
        seed_ = (x ^= (x<<5));
        return x;
    }

    unsigned    operator()() { return get(); }
};
#endif



/// 周期2**64 - 1のxor shift 乱数. (paper文中のabc3組の内の1つを適当に設定)
template<>
class XorShiftRand<64> {
    unsigned    seed_[2];
public:
    XorShiftRand(unsigned s=0) { init(s); }

    void init(unsigned s) {
        seed_[0] = s = 1812433253U * (s ^ (s>>30)) + 1;
        seed_[1]     = 1812433253U * (s ^ (s>>30)) + 2;
    }

    unsigned get() {
        enum { A =10, B =13, C =10 };       // [10,13,10][8,9,22][2,7,3][23,3,24]
        unsigned  t, y;
        unsigned* a = seed_;
        t    = a[0];
        t    = (t ^ (t<<A));
        a[0] = y = a[1];
        t    = (y ^ (y>>C)) ^ (t ^ (t>>B));
        a[1] = t;
        return t;
    }

    unsigned    operator()() { return get(); }
};



/// 周期2**96 - 1のxor shift 乱数. (paper文中のabc3組の内の1つを適当に設定)
template<>
class XorShiftRand<96> {
    unsigned    seed_[3];
public:
    XorShiftRand(unsigned s=0) { init(s); }

    void init(unsigned s) {
        for (unsigned i = 0; i < 3; ++i)
            seed_[i] = s = 1812433253U * (s ^ (s>>30)) + i+1;
    }

    unsigned get() {
        enum { A =10, B = 1, C =26 };       // [10,5,26][13,19,3][1,17,2][10,1,26]
        unsigned  t, z;
        unsigned* a = seed_;
        t    = a[0];
        t    = (t ^ (t<<A));
        a[0] = a[1];
        a[1] = z = a[2];
        t    = (z ^ (z>>C)) ^ (t ^ (t>>B));
        a[2] = t;
        return t;
    }

    unsigned    operator()() { return get(); }
};



/// 周期2**128 - 1のxor shift 乱数. (paper文中のもの)
template<>
class XorShiftRand<128> {
    unsigned    seed_[4];
public:
    XorShiftRand(unsigned s=0) { init(s); }

    void init(unsigned s) {
        for (unsigned i = 0; i < 4; ++i)
            seed_[i] = s = 1812433253U * (s ^ (s>>30)) + i+1;
    }

    unsigned get() {
        enum { A =11, B = 8, C =19 };
        unsigned  t, w;
        unsigned* a = seed_;
        t    = a[0];
        a[0] = a[1];
        a[1] = a[2];
        a[2] = w = a[3];
        t    = t ^ (t<<A);
        w    = (w ^ (w>>C)) ^ (t ^ (t>>B));
        a[3] = w;
        return w;
    }

    unsigned    operator()() { return get(); }
};



/// 周期 2**160 - 1 のxor shift 乱数. (paper文中のabc3組の内の1つを適当に設定)
template<>
class XorShiftRand<160> {
    unsigned    seed_[5];
public:
    XorShiftRand(unsigned s=0) { init(s); }

    void init(unsigned s) {
        for (unsigned i = 0; i < 5; ++i)
            seed_[i] = s = 1812433253U * (s ^ (s>>30)) + i+1;
    }

    unsigned get() {
        enum { A = 2, B = 1, C = 4 };   // [2,1,4][7,13,6][1,1,20]
        unsigned  t, v;
        unsigned* a = seed_;
        t    = a[0];
        a[0] = a[1];
        a[1] = a[2];
        a[2] = a[3];
        a[3] = v = a[4];
        //t  = (t ^ (t>>A));
        t    = (t ^ (t<<A));
        v    = (v ^ (v>>C)) ^ (t ^ (t>>B));
        a[4] = v;
        return v;
    }

    unsigned    operator()() { return get(); }
};



/// 周期 2**192 - 232 のxor shift 乱数. (paper.pdf: xorwow())
template<>
class XorShiftRand<192> {
    unsigned    seed_[6];
public:
    XorShiftRand(unsigned s=0) { init(s); }

    void init(unsigned s) {
        for (unsigned i = 0; i < 6; ++i)
            seed_[i] = s = 1812433253U * (s ^ (s>>30)) + i+1;
    }

    unsigned get() {
        unsigned  t, v;
        unsigned* a = seed_;
        t    = a[0];
        a[0] = a[1];
        a[1] = a[2];
        a[2] = a[3];
        a[3] = v = a[4];
        t    = (t ^ (t>>2));
        v    = (v ^ (v<<4)) ^ (t ^ (t<<1));
        a[4] = v;
        t    = (a[5] += 362437);
        t   += v;
        return t;
    }

    unsigned    operator()() { return get(); }
};



#ifdef XORSHIFTRAND_TEST
/// 周期 2**256 - 1 のxor shift 乱数. (xorshift.pdf文中の)
template<>
class XorShiftRand<256> {
    unsigned    k_;
    unsigned    seed_[8];
public:
    XorShiftRand(unsigned s=0) { init(s); }

    void init(unsigned s) {
        k_ = 0;
        for (unsigned i = 0; i < 8; ++i)
            seed_[i] = s = 1812433253U * (s ^ (s>>30)) + i+1;
    }

    unsigned get() {
        unsigned    t, y;
        unsigned*   a = seed_;
        unsigned    k = k_;
        t    = a[(k+7) & 0x7U]; t = t ^ (t<<13); y = t ^ (t<< 9);
        t    = a[(k+4) & 0x7U];                  y^= t ^ (t<< 7);
        t    = a[(k+3) & 0x7U];                  y^= t ^ (t>> 3);
        t    = a[(k+1) & 0x7U];                  y^= t ^ (t>>10);
        t    = a[k           ]; t = t ^ (t>> 7); y^= t ^ (t<<24);
        a[k] = y;
        k_   =   (k+1) & 0x7U;
        return y;
    }

    unsigned    operator()() { return get(); }
};
#endif


#endif