williamr@2: /* boost random/subtract_with_carry.hpp header file williamr@2: * williamr@2: * Copyright Jens Maurer 2002 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: subtract_with_carry.hpp,v 1.24 2005/05/21 15:57:00 dgregor Exp $ williamr@2: * williamr@2: * Revision history williamr@2: * 2002-03-02 created williamr@2: */ williamr@2: williamr@2: #ifndef BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP williamr@2: #define BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP williamr@2: williamr@2: #include williamr@2: #include williamr@2: #include // std::equal williamr@2: #include williamr@2: #include // std::pow williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: williamr@2: williamr@2: namespace boost { williamr@2: namespace random { williamr@2: williamr@2: #if BOOST_WORKAROUND(_MSC_FULL_VER, BOOST_TESTED_AT(13102292)) && BOOST_MSVC > 1300 williamr@2: # define BOOST_RANDOM_EXTRACT_SWC_01 williamr@2: #endif williamr@2: williamr@2: #if defined(__APPLE_CC__) && defined(__GNUC__) && (__GNUC__ == 3) && (__GNUC_MINOR__ <= 3) williamr@2: # define BOOST_RANDOM_EXTRACT_SWC_01 williamr@2: #endif williamr@2: williamr@2: # ifdef BOOST_RANDOM_EXTRACT_SWC_01 williamr@2: namespace detail williamr@2: { williamr@2: template williamr@2: void extract_subtract_with_carry_01( williamr@2: IStream& is williamr@2: , SubtractWithCarry& f williamr@2: , RealType& carry williamr@2: , RealType* x williamr@2: , RealType modulus) williamr@2: { williamr@2: RealType value; williamr@2: for(unsigned int j = 0; j < f.long_lag; ++j) { williamr@2: is >> value >> std::ws; williamr@2: x[j] = value / modulus; williamr@2: } williamr@2: is >> value >> std::ws; williamr@2: carry = value / modulus; williamr@2: } williamr@2: } williamr@2: # endif williamr@2: // subtract-with-carry generator williamr@2: // Marsaglia and Zaman williamr@2: williamr@2: template williamr@2: class subtract_with_carry williamr@2: { williamr@2: public: williamr@2: typedef IntType result_type; williamr@2: BOOST_STATIC_CONSTANT(bool, has_fixed_range = true); williamr@2: BOOST_STATIC_CONSTANT(result_type, min_value = 0); williamr@2: BOOST_STATIC_CONSTANT(result_type, max_value = m-1); williamr@2: BOOST_STATIC_CONSTANT(result_type, modulus = m); williamr@2: BOOST_STATIC_CONSTANT(unsigned int, long_lag = r); williamr@2: BOOST_STATIC_CONSTANT(unsigned int, short_lag = s); williamr@2: williamr@2: subtract_with_carry() { williamr@2: // MSVC fails BOOST_STATIC_ASSERT with std::numeric_limits at class scope williamr@2: #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS williamr@2: BOOST_STATIC_ASSERT(std::numeric_limits::is_signed); williamr@2: BOOST_STATIC_ASSERT(std::numeric_limits::is_integer); williamr@2: #endif williamr@2: seed(); williamr@2: } williamr@2: explicit subtract_with_carry(uint32_t value) { seed(value); } williamr@2: template williamr@2: explicit subtract_with_carry(Generator & gen) { seed(gen); } williamr@2: template subtract_with_carry(It& first, It last) { seed(first,last); } williamr@2: williamr@2: // compiler-generated copy ctor and assignment operator are fine williamr@2: williamr@2: void seed(uint32_t value = 19780503u) williamr@2: { williamr@2: random::linear_congruential intgen(value); williamr@2: seed(intgen); 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 template member functions. williamr@2: template williamr@2: void seed(Generator & gen) williamr@2: { williamr@2: // I could have used std::generate_n, but it takes "gen" by value williamr@2: for(unsigned int j = 0; j < long_lag; ++j) williamr@2: x[j] = gen() % modulus; williamr@2: carry = (x[long_lag-1] == 0); williamr@2: k = 0; williamr@2: } williamr@2: williamr@2: template williamr@2: void seed(It& first, It last) williamr@2: { williamr@2: unsigned int j; williamr@2: for(j = 0; j < long_lag && first != last; ++j, ++first) williamr@2: x[j] = *first % modulus; williamr@2: if(first == last && j < long_lag) williamr@2: throw std::invalid_argument("subtract_with_carry::seed"); williamr@2: carry = (x[long_lag-1] == 0); williamr@2: k = 0; williamr@2: } williamr@2: williamr@2: result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return min_value; } williamr@2: result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return max_value; } williamr@2: williamr@2: result_type operator()() williamr@2: { williamr@2: int short_index = k - short_lag; williamr@2: if(short_index < 0) williamr@2: short_index += long_lag; williamr@2: IntType delta; williamr@2: if (x[short_index] >= x[k] + carry) { williamr@2: // x(n) >= 0 williamr@2: delta = x[short_index] - (x[k] + carry); williamr@2: carry = 0; williamr@2: } else { williamr@2: // x(n) < 0 williamr@2: delta = modulus - x[k] - carry + x[short_index]; williamr@2: carry = 1; williamr@2: } williamr@2: x[k] = delta; williamr@2: ++k; williamr@2: if(k >= long_lag) williamr@2: k = 0; williamr@2: return delta; williamr@2: } williamr@2: williamr@2: public: williamr@2: static bool validation(result_type x) { return x == val; } 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, williamr@2: const subtract_with_carry& f) williamr@2: { williamr@2: for(unsigned int j = 0; j < f.long_lag; ++j) williamr@2: os << f.compute(j) << " "; williamr@2: os << f.carry << " "; williamr@2: return os; williamr@2: } williamr@2: williamr@2: template williamr@2: friend std::basic_istream& williamr@2: operator>>(std::basic_istream& is, subtract_with_carry& f) williamr@2: { williamr@2: for(unsigned int j = 0; j < f.long_lag; ++j) williamr@2: is >> f.x[j] >> std::ws; williamr@2: is >> f.carry >> std::ws; williamr@2: f.k = 0; williamr@2: return is; williamr@2: } williamr@2: #endif williamr@2: williamr@2: friend bool operator==(const subtract_with_carry& x, const subtract_with_carry& y) williamr@2: { williamr@2: for(unsigned int j = 0; j < r; ++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 subtract_with_carry& x, const subtract_with_carry& y) williamr@2: { return !(x == y); } williamr@2: #else williamr@2: // Use a member function; Streamable concept not supported. williamr@2: bool operator==(const subtract_with_carry& rhs) const williamr@2: { williamr@2: for(unsigned int j = 0; j < r; ++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 subtract_with_carry& rhs) const williamr@2: { return !(*this == rhs); } williamr@2: #endif williamr@2: williamr@2: private: williamr@2: // returns x(i-r+index), where index is in 0..r-1 williamr@2: IntType compute(unsigned int index) const williamr@2: { williamr@2: return x[(k+index) % long_lag]; williamr@2: } williamr@2: williamr@2: // state representation; next output (state) is x(i) williamr@2: // x[0] ... x[k] x[k+1] ... x[long_lag-1] represents williamr@2: // x(i-k) ... x(i) x(i+1) ... x(i-k+long_lag-1) williamr@2: // speed: base: 20-25 nsec williamr@2: // ranlux_4: 230 nsec, ranlux_7: 430 nsec, ranlux_14: 810 nsec williamr@2: // This state representation makes operator== and save/restore more williamr@2: // difficult, because we've already computed "too much" and thus williamr@2: // have to undo some steps to get at x(i-r) etc. williamr@2: williamr@2: // state representation: next output (state) is x(i) williamr@2: // x[0] ... x[k] x[k+1] ... x[long_lag-1] represents williamr@2: // x(i-k) ... x(i) x(i-long_lag+1) ... x(i-k-1) williamr@2: // speed: base 28 nsec williamr@2: // ranlux_4: 370 nsec, ranlux_7: 688 nsec, ranlux_14: 1343 nsec williamr@2: IntType x[long_lag]; williamr@2: unsigned int k; williamr@2: int carry; 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 subtract_with_carry::has_fixed_range; williamr@2: template williamr@2: const IntType subtract_with_carry::min_value; williamr@2: template williamr@2: const IntType subtract_with_carry::max_value; williamr@2: template williamr@2: const IntType subtract_with_carry::modulus; williamr@2: template williamr@2: const unsigned int subtract_with_carry::long_lag; williamr@2: template williamr@2: const unsigned int subtract_with_carry::short_lag; williamr@2: #endif williamr@2: williamr@2: williamr@2: // use a floating-point representation to produce values in [0..1) williamr@2: template williamr@2: class subtract_with_carry_01 williamr@2: { williamr@2: public: williamr@2: typedef RealType result_type; williamr@2: BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); williamr@2: BOOST_STATIC_CONSTANT(int, word_size = w); williamr@2: BOOST_STATIC_CONSTANT(unsigned int, long_lag = r); williamr@2: BOOST_STATIC_CONSTANT(unsigned int, short_lag = s); williamr@2: williamr@2: #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS williamr@2: BOOST_STATIC_ASSERT(!std::numeric_limits::is_integer); williamr@2: #endif williamr@2: williamr@2: subtract_with_carry_01() { init_modulus(); seed(); } williamr@2: explicit subtract_with_carry_01(uint32_t value) williamr@2: { init_modulus(); seed(value); } williamr@2: template subtract_with_carry_01(It& first, It last) williamr@2: { init_modulus(); seed(first,last); } williamr@2: williamr@2: private: williamr@2: void init_modulus() williamr@2: { williamr@2: #ifndef BOOST_NO_STDC_NAMESPACE williamr@2: // allow for Koenig lookup williamr@2: using std::pow; williamr@2: #endif williamr@2: _modulus = pow(RealType(2), word_size); williamr@2: } williamr@2: williamr@2: public: williamr@2: // compiler-generated copy ctor and assignment operator are fine williamr@2: williamr@2: void seed(uint32_t value = 19780503u) williamr@2: { williamr@2: #ifndef BOOST_NO_STDC_NAMESPACE williamr@2: // allow for Koenig lookup williamr@2: using std::fmod; williamr@2: #endif williamr@2: random::linear_congruential gen(value); williamr@2: unsigned long array[(w+31)/32 * long_lag]; williamr@2: for(unsigned int j = 0; j < sizeof(array)/sizeof(unsigned long); ++j) williamr@2: array[j] = gen(); williamr@2: unsigned long * start = array; williamr@2: seed(start, array + sizeof(array)/sizeof(unsigned long)); williamr@2: } williamr@2: williamr@2: template williamr@2: void seed(It& first, It last) williamr@2: { williamr@2: #ifndef BOOST_NO_STDC_NAMESPACE williamr@2: // allow for Koenig lookup williamr@2: using std::fmod; williamr@2: using std::pow; williamr@2: #endif williamr@2: unsigned long mask = ~((~0u) << (w%32)); // now lowest (w%32) bits set williamr@2: RealType two32 = pow(RealType(2), 32); williamr@2: unsigned int j; williamr@2: for(j = 0; j < long_lag && first != last; ++j) { williamr@2: x[j] = RealType(0); williamr@2: for(int i = 0; i < w/32 && first != last; ++i, ++first) williamr@2: x[j] += *first / pow(two32,i+1); williamr@2: if(first != last && mask != 0) { williamr@2: x[j] += fmod((*first & mask) / _modulus, RealType(1)); williamr@2: ++first; williamr@2: } williamr@2: } williamr@2: if(first == last && j < long_lag) williamr@2: throw std::invalid_argument("subtract_with_carry_01::seed"); williamr@2: carry = (x[long_lag-1] ? 0 : 1 / _modulus); williamr@2: k = 0; williamr@2: } williamr@2: williamr@2: result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return result_type(0); } williamr@2: result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return result_type(1); } williamr@2: williamr@2: result_type operator()() williamr@2: { williamr@2: int short_index = k - short_lag; williamr@2: if(short_index < 0) williamr@2: short_index += long_lag; williamr@2: RealType delta = x[short_index] - x[k] - carry; williamr@2: if(delta < 0) { williamr@2: delta += RealType(1); williamr@2: carry = RealType(1)/_modulus; williamr@2: } else { williamr@2: carry = 0; williamr@2: } williamr@2: x[k] = delta; williamr@2: ++k; williamr@2: if(k >= long_lag) williamr@2: k = 0; williamr@2: return delta; williamr@2: } williamr@2: williamr@2: static bool validation(result_type x) williamr@2: { return x == val/pow(RealType(2), word_size); } 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, williamr@2: const subtract_with_carry_01& f) williamr@2: { williamr@2: #ifndef BOOST_NO_STDC_NAMESPACE williamr@2: // allow for Koenig lookup williamr@2: using std::pow; williamr@2: #endif williamr@2: std::ios_base::fmtflags oldflags = os.flags(os.dec | os.fixed | os.left); williamr@2: for(unsigned int j = 0; j < f.long_lag; ++j) williamr@2: os << (f.compute(j) * f._modulus) << " "; williamr@2: os << (f.carry * f._modulus); williamr@2: os.flags(oldflags); williamr@2: return os; williamr@2: } williamr@2: williamr@2: template williamr@2: friend std::basic_istream& williamr@2: operator>>(std::basic_istream& is, subtract_with_carry_01& f) williamr@2: { williamr@2: # ifdef BOOST_RANDOM_EXTRACT_SWC_01 williamr@2: detail::extract_subtract_with_carry_01(is, f, f.carry, f.x, f._modulus); williamr@2: # else williamr@2: // MSVC (up to 7.1) and Borland (up to 5.64) don't handle the template type williamr@2: // parameter "RealType" available from the class template scope, so use williamr@2: // the member typedef williamr@2: typename subtract_with_carry_01::result_type value; williamr@2: for(unsigned int j = 0; j < long_lag; ++j) { williamr@2: is >> value >> std::ws; williamr@2: f.x[j] = value / f._modulus; williamr@2: } williamr@2: is >> value >> std::ws; williamr@2: f.carry = value / f._modulus; williamr@2: # endif williamr@2: f.k = 0; williamr@2: return is; williamr@2: } williamr@2: #endif williamr@2: williamr@2: friend bool operator==(const subtract_with_carry_01& x, williamr@2: const subtract_with_carry_01& y) williamr@2: { williamr@2: for(unsigned int j = 0; j < r; ++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 subtract_with_carry_01& x, williamr@2: const subtract_with_carry_01& y) williamr@2: { return !(x == y); } williamr@2: #else williamr@2: // Use a member function; Streamable concept not supported. williamr@2: bool operator==(const subtract_with_carry_01& rhs) const williamr@2: { williamr@2: for(unsigned int j = 0; j < r; ++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 subtract_with_carry_01& rhs) const williamr@2: { return !(*this == rhs); } williamr@2: #endif williamr@2: williamr@2: private: williamr@2: RealType compute(unsigned int index) const; williamr@2: unsigned int k; williamr@2: RealType carry; williamr@2: RealType x[long_lag]; williamr@2: RealType _modulus; 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 subtract_with_carry_01::has_fixed_range; williamr@2: template williamr@2: const int subtract_with_carry_01::word_size; williamr@2: template williamr@2: const unsigned int subtract_with_carry_01::long_lag; williamr@2: template williamr@2: const unsigned int subtract_with_carry_01::short_lag; williamr@2: #endif williamr@2: williamr@2: template williamr@2: RealType subtract_with_carry_01::compute(unsigned int index) const williamr@2: { williamr@2: return x[(k+index) % long_lag]; williamr@2: } williamr@2: williamr@2: williamr@2: } // namespace random williamr@2: } // namespace boost williamr@2: williamr@2: #endif // BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP