williamr@2: /* boost random/mersenne_twister.hpp header file williamr@2: * williamr@2: * Copyright Jens Maurer 2000-2001 williamr@2: * Distributed under the Boost Software License, Version 1.0. (See williamr@2: * accompanying file LICENSE_1_0.txt or copy at williamr@2: * http://www.boost.org/LICENSE_1_0.txt) williamr@2: * williamr@2: * See http://www.boost.org for most recent version including documentation. williamr@2: * williamr@2: * $Id: mersenne_twister.hpp,v 1.20 2005/07/21 22:04:31 jmaurer Exp $ williamr@2: * williamr@2: * Revision history williamr@2: * 2001-02-18 moved to individual header files williamr@2: */ williamr@2: williamr@2: #ifndef BOOST_RANDOM_MERSENNE_TWISTER_HPP williamr@2: #define BOOST_RANDOM_MERSENNE_TWISTER_HPP williamr@2: williamr@2: #include williamr@2: #include // std::copy williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: williamr@2: namespace boost { williamr@2: namespace random { williamr@2: williamr@2: // http://www.math.keio.ac.jp/matumoto/emt.html williamr@2: template williamr@2: class mersenne_twister williamr@2: { williamr@2: public: williamr@2: typedef UIntType result_type; williamr@2: BOOST_STATIC_CONSTANT(int, word_size = w); williamr@2: BOOST_STATIC_CONSTANT(int, state_size = n); williamr@2: BOOST_STATIC_CONSTANT(int, shift_size = m); williamr@2: BOOST_STATIC_CONSTANT(int, mask_bits = r); williamr@2: BOOST_STATIC_CONSTANT(UIntType, parameter_a = a); williamr@2: BOOST_STATIC_CONSTANT(int, output_u = u); williamr@2: BOOST_STATIC_CONSTANT(int, output_s = s); williamr@2: BOOST_STATIC_CONSTANT(UIntType, output_b = b); williamr@2: BOOST_STATIC_CONSTANT(int, output_t = t); williamr@2: BOOST_STATIC_CONSTANT(UIntType, output_c = c); williamr@2: BOOST_STATIC_CONSTANT(int, output_l = l); williamr@2: williamr@2: BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); williamr@2: williamr@2: mersenne_twister() { seed(); } williamr@2: williamr@2: #if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x520) williamr@2: // Work around overload resolution problem (Gennadiy E. Rozental) williamr@2: explicit mersenne_twister(const UIntType& value) williamr@2: #else williamr@2: explicit mersenne_twister(UIntType value) williamr@2: #endif williamr@2: { seed(value); } williamr@2: template mersenne_twister(It& first, It last) { seed(first,last); } williamr@2: williamr@2: template williamr@2: explicit mersenne_twister(Generator & gen) { seed(gen); } williamr@2: williamr@2: // compiler-generated copy ctor and assignment operator are fine williamr@2: williamr@2: void seed() { seed(UIntType(5489)); } williamr@2: williamr@2: #if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x520) williamr@2: // Work around overload resolution problem (Gennadiy E. Rozental) williamr@2: void seed(const UIntType& value) williamr@2: #else williamr@2: void seed(UIntType value) williamr@2: #endif williamr@2: { williamr@2: // New seeding algorithm from williamr@2: // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html williamr@2: // In the previous versions, MSBs of the seed affected only MSBs of the williamr@2: // state x[]. williamr@2: const UIntType mask = ~0u; williamr@2: x[0] = value & mask; williamr@2: for (i = 1; i < n; i++) { williamr@2: // See Knuth "The Art of Computer Programming" Vol. 2, 3rd ed., page 106 williamr@2: x[i] = (1812433253UL * (x[i-1] ^ (x[i-1] >> (w-2))) + i) & mask; williamr@2: } williamr@2: } williamr@2: williamr@2: // For GCC, moving this function out-of-line prevents inlining, which may williamr@2: // reduce overall object code size. However, MSVC does not grok williamr@2: // out-of-line definitions of member function templates. williamr@2: template williamr@2: void seed(Generator & gen) williamr@2: { williamr@2: #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS williamr@2: BOOST_STATIC_ASSERT(!std::numeric_limits::is_signed); williamr@2: #endif williamr@2: // I could have used std::generate_n, but it takes "gen" by value williamr@2: for(int j = 0; j < n; j++) williamr@2: x[j] = gen(); williamr@2: i = n; williamr@2: } williamr@2: williamr@2: template williamr@2: void seed(It& first, It last) williamr@2: { williamr@2: int j; williamr@2: for(j = 0; j < n && first != last; ++j, ++first) williamr@2: x[j] = *first; williamr@2: i = n; williamr@2: if(first == last && j < n) williamr@2: throw std::invalid_argument("mersenne_twister::seed"); williamr@2: } williamr@2: williamr@2: result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 0; } williamr@2: result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const williamr@2: { williamr@2: // avoid "left shift count >= with of type" warning williamr@2: result_type res = 0; williamr@2: for(int i = 0; i < w; ++i) williamr@2: res |= (1u << i); williamr@2: return res; williamr@2: } williamr@2: williamr@2: result_type operator()(); williamr@2: static bool validation(result_type v) { return val == v; } williamr@2: williamr@2: #ifndef BOOST_NO_OPERATORS_IN_NAMESPACE williamr@2: williamr@2: #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS williamr@2: template williamr@2: friend std::basic_ostream& williamr@2: operator<<(std::basic_ostream& os, const mersenne_twister& mt) williamr@2: { williamr@2: for(int j = 0; j < mt.state_size; ++j) williamr@2: os << mt.compute(j) << " "; williamr@2: return os; williamr@2: } williamr@2: williamr@2: template williamr@2: friend std::basic_istream& williamr@2: operator>>(std::basic_istream& is, mersenne_twister& mt) williamr@2: { williamr@2: for(int j = 0; j < mt.state_size; ++j) williamr@2: is >> mt.x[j] >> std::ws; williamr@2: // MSVC (up to 7.1) and Borland (up to 5.64) don't handle the template williamr@2: // value parameter "n" available from the class template scope, so use williamr@2: // the static constant with the same value williamr@2: mt.i = mt.state_size; williamr@2: return is; williamr@2: } williamr@2: #endif williamr@2: williamr@2: friend bool operator==(const mersenne_twister& x, const mersenne_twister& y) williamr@2: { williamr@2: for(int j = 0; j < state_size; ++j) williamr@2: if(x.compute(j) != y.compute(j)) williamr@2: return false; williamr@2: return true; williamr@2: } williamr@2: williamr@2: friend bool operator!=(const mersenne_twister& x, const mersenne_twister& y) williamr@2: { return !(x == y); } williamr@2: #else williamr@2: // Use a member function; Streamable concept not supported. williamr@2: bool operator==(const mersenne_twister& rhs) const williamr@2: { williamr@2: for(int j = 0; j < state_size; ++j) williamr@2: if(compute(j) != rhs.compute(j)) williamr@2: return false; williamr@2: return true; williamr@2: } williamr@2: williamr@2: bool operator!=(const mersenne_twister& rhs) const williamr@2: { return !(*this == rhs); } williamr@2: #endif williamr@2: williamr@2: private: williamr@2: // returns x(i-n+index), where index is in 0..n-1 williamr@2: UIntType compute(unsigned int index) const williamr@2: { williamr@2: // equivalent to (i-n+index) % 2n, but doesn't produce negative numbers williamr@2: return x[ (i + n + index) % (2*n) ]; williamr@2: } williamr@2: void twist(int block); williamr@2: williamr@2: // state representation: next output is o(x(i)) williamr@2: // x[0] ... x[k] x[k+1] ... x[n-1] x[n] ... x[2*n-1] represents williamr@2: // x(i-k) ... x(i) x(i+1) ... x(i-k+n-1) x(i-k-n) ... x[i(i-k-1)] williamr@2: // The goal is to always have x(i-n) ... x(i-1) available for williamr@2: // operator== and save/restore. williamr@2: williamr@2: UIntType x[2*n]; williamr@2: int i; williamr@2: }; williamr@2: williamr@2: #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION williamr@2: // A definition is required even for integral static constants williamr@2: template williamr@2: const bool mersenne_twister::has_fixed_range; williamr@2: template williamr@2: const int mersenne_twister::state_size; williamr@2: template williamr@2: const int mersenne_twister::shift_size; williamr@2: template williamr@2: const int mersenne_twister::mask_bits; williamr@2: template williamr@2: const UIntType mersenne_twister::parameter_a; williamr@2: template williamr@2: const int mersenne_twister::output_u; williamr@2: template williamr@2: const int mersenne_twister::output_s; williamr@2: template williamr@2: const UIntType mersenne_twister::output_b; williamr@2: template williamr@2: const int mersenne_twister::output_t; williamr@2: template williamr@2: const UIntType mersenne_twister::output_c; williamr@2: template williamr@2: const int mersenne_twister::output_l; williamr@2: #endif williamr@2: williamr@2: template williamr@2: void mersenne_twister::twist(int block) williamr@2: { williamr@2: const UIntType upper_mask = (~0u) << r; williamr@2: const UIntType lower_mask = ~upper_mask; williamr@2: williamr@2: if(block == 0) { williamr@2: for(int j = n; j < 2*n; j++) { williamr@2: UIntType y = (x[j-n] & upper_mask) | (x[j-(n-1)] & lower_mask); williamr@2: x[j] = x[j-(n-m)] ^ (y >> 1) ^ (y&1 ? a : 0); williamr@2: } williamr@2: } else if (block == 1) { williamr@2: // split loop to avoid costly modulo operations williamr@2: { // extra scope for MSVC brokenness w.r.t. for scope williamr@2: for(int j = 0; j < n-m; j++) { williamr@2: UIntType y = (x[j+n] & upper_mask) | (x[j+n+1] & lower_mask); williamr@2: x[j] = x[j+n+m] ^ (y >> 1) ^ (y&1 ? a : 0); williamr@2: } williamr@2: } williamr@2: williamr@2: for(int j = n-m; j < n-1; j++) { williamr@2: UIntType y = (x[j+n] & upper_mask) | (x[j+n+1] & lower_mask); williamr@2: x[j] = x[j-(n-m)] ^ (y >> 1) ^ (y&1 ? a : 0); williamr@2: } williamr@2: // last iteration williamr@2: UIntType y = (x[2*n-1] & upper_mask) | (x[0] & lower_mask); williamr@2: x[n-1] = x[m-1] ^ (y >> 1) ^ (y&1 ? a : 0); williamr@2: i = 0; williamr@2: } williamr@2: } williamr@2: williamr@2: template williamr@2: inline typename mersenne_twister::result_type williamr@2: mersenne_twister::operator()() williamr@2: { williamr@2: if(i == n) williamr@2: twist(0); williamr@2: else if(i >= 2*n) williamr@2: twist(1); williamr@2: // Step 4 williamr@2: UIntType z = x[i]; williamr@2: ++i; williamr@2: z ^= (z >> u); williamr@2: z ^= ((z << s) & b); williamr@2: z ^= ((z << t) & c); williamr@2: z ^= (z >> l); williamr@2: return z; williamr@2: } williamr@2: williamr@2: } // namespace random williamr@2: williamr@2: williamr@2: typedef random::mersenne_twister mt11213b; williamr@2: williamr@2: // validation by experiment from mt19937.c williamr@2: typedef random::mersenne_twister mt19937; williamr@2: williamr@2: } // namespace boost williamr@2: williamr@2: BOOST_RANDOM_PTR_HELPER_SPEC(boost::mt19937) williamr@2: williamr@2: #endif // BOOST_RANDOM_MERSENNE_TWISTER_HPP