/* boost random/subtract_with_carry.hpp header file * * Copyright Jens Maurer 2002 * Distributed under the Boost Software License, Version 1.0. (See * accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * See http://www.boost.org for most recent version including documentation. * * $Id: subtract_with_carry.hpp 60755 2010-03-22 00:45:06Z steven_watanabe $ * * Revision history * 2002-03-02 created */ #ifndef BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP #define BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP #include #include #include // std::equal #include #include // std::pow #include #include #include #include #include #include #include #include namespace boost { namespace random { #if BOOST_WORKAROUND(_MSC_FULL_VER, BOOST_TESTED_AT(13102292)) && BOOST_MSVC > 1300 # define BOOST_RANDOM_EXTRACT_SWC_01 #endif #if defined(__APPLE_CC__) && defined(__GNUC__) && (__GNUC__ == 3) && (__GNUC_MINOR__ <= 3) # define BOOST_RANDOM_EXTRACT_SWC_01 #endif # ifdef BOOST_RANDOM_EXTRACT_SWC_01 namespace detail { template void extract_subtract_with_carry_01( IStream& is , SubtractWithCarry& f , RealType& carry , RealType* x , RealType modulus) { RealType value; for(unsigned int j = 0; j < f.long_lag; ++j) { is >> value >> std::ws; x[j] = value / modulus; } is >> value >> std::ws; carry = value / modulus; } } # endif /** * Instantiations of @c subtract_with_carry model a * \pseudo_random_number_generator. The algorithm is * described in * * @blockquote * "A New Class of Random Number Generators", George * Marsaglia and Arif Zaman, Annals of Applied Probability, * Volume 1, Number 3 (1991), 462-480. * @endblockquote */ template class subtract_with_carry { public: typedef IntType result_type; BOOST_STATIC_CONSTANT(bool, has_fixed_range = true); BOOST_STATIC_CONSTANT(result_type, min_value = 0); BOOST_STATIC_CONSTANT(result_type, max_value = m-1); BOOST_STATIC_CONSTANT(result_type, modulus = m); BOOST_STATIC_CONSTANT(unsigned int, long_lag = r); BOOST_STATIC_CONSTANT(unsigned int, short_lag = s); subtract_with_carry() { // MSVC fails BOOST_STATIC_ASSERT with std::numeric_limits at class scope #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS BOOST_STATIC_ASSERT(std::numeric_limits::is_signed); BOOST_STATIC_ASSERT(std::numeric_limits::is_integer); #endif seed(); } BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry, uint32_t, value) { seed(value); } BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(subtract_with_carry, Generator, gen) { seed(gen); } template subtract_with_carry(It& first, It last) { seed(first,last); } // compiler-generated copy ctor and assignment operator are fine void seed() { seed(19780503u); } BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry, uint32_t, value) { random::linear_congruential intgen(value); seed(intgen); } // For GCC, moving this function out-of-line prevents inlining, which may // reduce overall object code size. However, MSVC does not grok // out-of-line template member functions. BOOST_RANDOM_DETAIL_GENERATOR_SEED(subtract_with_carry, Generator, gen) { // I could have used std::generate_n, but it takes "gen" by value for(unsigned int j = 0; j < long_lag; ++j) x[j] = gen() % modulus; carry = (x[long_lag-1] == 0); k = 0; } template void seed(It& first, It last) { unsigned int j; for(j = 0; j < long_lag && first != last; ++j, ++first) x[j] = *first % modulus; if(first == last && j < long_lag) throw std::invalid_argument("subtract_with_carry::seed"); carry = (x[long_lag-1] == 0); k = 0; } result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return min_value; } result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return max_value; } result_type operator()() { int short_index = k - short_lag; if(short_index < 0) short_index += long_lag; IntType delta; if (x[short_index] >= x[k] + carry) { // x(n) >= 0 delta = x[short_index] - (x[k] + carry); carry = 0; } else { // x(n) < 0 delta = modulus - x[k] - carry + x[short_index]; carry = 1; } x[k] = delta; ++k; if(k >= long_lag) k = 0; return delta; } public: static bool validation(result_type x) { return x == val; } #ifndef BOOST_NO_OPERATORS_IN_NAMESPACE #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS template friend std::basic_ostream& operator<<(std::basic_ostream& os, const subtract_with_carry& f) { for(unsigned int j = 0; j < f.long_lag; ++j) os << f.compute(j) << " "; os << f.carry << " "; return os; } template friend std::basic_istream& operator>>(std::basic_istream& is, subtract_with_carry& f) { for(unsigned int j = 0; j < f.long_lag; ++j) is >> f.x[j] >> std::ws; is >> f.carry >> std::ws; f.k = 0; return is; } #endif friend bool operator==(const subtract_with_carry& x, const subtract_with_carry& y) { for(unsigned int j = 0; j < r; ++j) if(x.compute(j) != y.compute(j)) return false; return true; } friend bool operator!=(const subtract_with_carry& x, const subtract_with_carry& y) { return !(x == y); } #else // Use a member function; Streamable concept not supported. bool operator==(const subtract_with_carry& rhs) const { for(unsigned int j = 0; j < r; ++j) if(compute(j) != rhs.compute(j)) return false; return true; } bool operator!=(const subtract_with_carry& rhs) const { return !(*this == rhs); } #endif private: /// \cond hide_private_members // returns x(i-r+index), where index is in 0..r-1 IntType compute(unsigned int index) const { return x[(k+index) % long_lag]; } /// \endcond // state representation; next output (state) is x(i) // x[0] ... x[k] x[k+1] ... x[long_lag-1] represents // x(i-k) ... x(i) x(i+1) ... x(i-k+long_lag-1) // speed: base: 20-25 nsec // ranlux_4: 230 nsec, ranlux_7: 430 nsec, ranlux_14: 810 nsec // This state representation makes operator== and save/restore more // difficult, because we've already computed "too much" and thus // have to undo some steps to get at x(i-r) etc. // state representation: next output (state) is x(i) // x[0] ... x[k] x[k+1] ... x[long_lag-1] represents // x(i-k) ... x(i) x(i-long_lag+1) ... x(i-k-1) // speed: base 28 nsec // ranlux_4: 370 nsec, ranlux_7: 688 nsec, ranlux_14: 1343 nsec IntType x[long_lag]; unsigned int k; int carry; }; #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION // A definition is required even for integral static constants template const bool subtract_with_carry::has_fixed_range; template const IntType subtract_with_carry::min_value; template const IntType subtract_with_carry::max_value; template const IntType subtract_with_carry::modulus; template const unsigned int subtract_with_carry::long_lag; template const unsigned int subtract_with_carry::short_lag; #endif // use a floating-point representation to produce values in [0..1) /** @copydoc boost::random::subtract_with_carry */ template class subtract_with_carry_01 { public: typedef RealType result_type; BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); BOOST_STATIC_CONSTANT(int, word_size = w); BOOST_STATIC_CONSTANT(unsigned int, long_lag = r); BOOST_STATIC_CONSTANT(unsigned int, short_lag = s); #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS BOOST_STATIC_ASSERT(!std::numeric_limits::is_integer); #endif subtract_with_carry_01() { init_modulus(); seed(); } explicit subtract_with_carry_01(uint32_t value) { init_modulus(); seed(value); } template subtract_with_carry_01(It& first, It last) { init_modulus(); seed(first,last); } private: /// \cond hide_private_members void init_modulus() { #ifndef BOOST_NO_STDC_NAMESPACE // allow for Koenig lookup using std::pow; #endif _modulus = pow(RealType(2), word_size); } /// \endcond hide_private_members public: // compiler-generated copy ctor and assignment operator are fine void seed(uint32_t value = 19780503u) { #ifndef BOOST_NO_STDC_NAMESPACE // allow for Koenig lookup using std::fmod; #endif random::linear_congruential gen(value); unsigned long array[(w+31)/32 * long_lag]; for(unsigned int j = 0; j < sizeof(array)/sizeof(unsigned long); ++j) array[j] = gen(); unsigned long * start = array; seed(start, array + sizeof(array)/sizeof(unsigned long)); } template void seed(It& first, It last) { #ifndef BOOST_NO_STDC_NAMESPACE // allow for Koenig lookup using std::fmod; using std::pow; #endif unsigned long mask = ~((~0u) << (w%32)); // now lowest (w%32) bits set RealType two32 = pow(RealType(2), 32); unsigned int j; for(j = 0; j < long_lag && first != last; ++j) { x[j] = RealType(0); for(int i = 0; i < w/32 && first != last; ++i, ++first) x[j] += *first / pow(two32,i+1); if(first != last && mask != 0) { x[j] += fmod((*first & mask) / _modulus, RealType(1)); ++first; } } if(first == last && j < long_lag) throw std::invalid_argument("subtract_with_carry_01::seed"); carry = (x[long_lag-1] ? 0 : 1 / _modulus); k = 0; } result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return result_type(0); } result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return result_type(1); } result_type operator()() { int short_index = k - short_lag; if(short_index < 0) short_index += long_lag; RealType delta = x[short_index] - x[k] - carry; if(delta < 0) { delta += RealType(1); carry = RealType(1)/_modulus; } else { carry = 0; } x[k] = delta; ++k; if(k >= long_lag) k = 0; return delta; } static bool validation(result_type x) { return x == val/pow(RealType(2), word_size); } #ifndef BOOST_NO_OPERATORS_IN_NAMESPACE #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS template friend std::basic_ostream& operator<<(std::basic_ostream& os, const subtract_with_carry_01& f) { #ifndef BOOST_NO_STDC_NAMESPACE // allow for Koenig lookup using std::pow; #endif std::ios_base::fmtflags oldflags = os.flags(os.dec | os.fixed | os.left); for(unsigned int j = 0; j < f.long_lag; ++j) os << (f.compute(j) * f._modulus) << " "; os << (f.carry * f._modulus); os.flags(oldflags); return os; } template friend std::basic_istream& operator>>(std::basic_istream& is, subtract_with_carry_01& f) { # ifdef BOOST_RANDOM_EXTRACT_SWC_01 detail::extract_subtract_with_carry_01(is, f, f.carry, f.x, f._modulus); # else // MSVC (up to 7.1) and Borland (up to 5.64) don't handle the template type // parameter "RealType" available from the class template scope, so use // the member typedef typename subtract_with_carry_01::result_type value; for(unsigned int j = 0; j < long_lag; ++j) { is >> value >> std::ws; f.x[j] = value / f._modulus; } is >> value >> std::ws; f.carry = value / f._modulus; # endif f.k = 0; return is; } #endif friend bool operator==(const subtract_with_carry_01& x, const subtract_with_carry_01& y) { for(unsigned int j = 0; j < r; ++j) if(x.compute(j) != y.compute(j)) return false; return true; } friend bool operator!=(const subtract_with_carry_01& x, const subtract_with_carry_01& y) { return !(x == y); } #else // Use a member function; Streamable concept not supported. bool operator==(const subtract_with_carry_01& rhs) const { for(unsigned int j = 0; j < r; ++j) if(compute(j) != rhs.compute(j)) return false; return true; } bool operator!=(const subtract_with_carry_01& rhs) const { return !(*this == rhs); } #endif private: /// \cond hide_private_members RealType compute(unsigned int index) const; /// \endcond unsigned int k; RealType carry; RealType x[long_lag]; RealType _modulus; }; #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION // A definition is required even for integral static constants template const bool subtract_with_carry_01::has_fixed_range; template const int subtract_with_carry_01::word_size; template const unsigned int subtract_with_carry_01::long_lag; template const unsigned int subtract_with_carry_01::short_lag; #endif /// \cond hide_private_members template RealType subtract_with_carry_01::compute(unsigned int index) const { return x[(k+index) % long_lag]; } /// \endcond } // namespace random } // namespace boost #endif // BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP