123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613 |
- /* 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$
- *
- * Revision history
- * 2002-03-02 created
- */
- #ifndef BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP
- #define BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP
- #include <boost/config/no_tr1/cmath.hpp> // std::pow
- #include <iostream>
- #include <algorithm> // std::equal
- #include <stdexcept>
- #include <boost/config.hpp>
- #include <boost/limits.hpp>
- #include <boost/cstdint.hpp>
- #include <boost/static_assert.hpp>
- #include <boost/integer/static_log2.hpp>
- #include <boost/integer/integer_mask.hpp>
- #include <boost/detail/workaround.hpp>
- #include <boost/random/detail/config.hpp>
- #include <boost/random/detail/seed.hpp>
- #include <boost/random/detail/operators.hpp>
- #include <boost/random/detail/seed_impl.hpp>
- #include <boost/random/detail/generator_seed_seq.hpp>
- #include <boost/random/linear_congruential.hpp>
- namespace boost {
- namespace random {
- namespace detail {
-
- struct subtract_with_carry_discard
- {
- template<class Engine>
- static void apply(Engine& eng, boost::uintmax_t z)
- {
- typedef typename Engine::result_type IntType;
- const std::size_t short_lag = Engine::short_lag;
- const std::size_t long_lag = Engine::long_lag;
- std::size_t k = eng.k;
- IntType carry = eng.carry;
- if(k != 0) {
- // increment k until it becomes 0.
- if(k < short_lag) {
- std::size_t limit = (short_lag - k) < z?
- short_lag : (k + static_cast<std::size_t>(z));
- for(std::size_t j = k; j < limit; ++j) {
- carry = eng.do_update(j, j + long_lag - short_lag, carry);
- }
- }
- std::size_t limit = (long_lag - k) < z?
- long_lag : (k + static_cast<std::size_t>(z));
- std::size_t start = (k < short_lag ? short_lag : k);
- for(std::size_t j = start; j < limit; ++j) {
- carry = eng.do_update(j, j - short_lag, carry);
- }
- }
- k = ((z % long_lag) + k) % long_lag;
- if(k < z) {
- // main loop: update full blocks from k = 0 to long_lag
- for(std::size_t i = 0; i < (z - k) / long_lag; ++i) {
- for(std::size_t j = 0; j < short_lag; ++j) {
- carry = eng.do_update(j, j + long_lag - short_lag, carry);
- }
- for(std::size_t j = short_lag; j < long_lag; ++j) {
- carry = eng.do_update(j, j - short_lag, carry);
- }
- }
- // Update the last partial block
- std::size_t limit = short_lag < k? short_lag : k;
- for(std::size_t j = 0; j < limit; ++j) {
- carry = eng.do_update(j, j + long_lag - short_lag, carry);
- }
- for(std::size_t j = short_lag; j < k; ++j) {
- carry = eng.do_update(j, j - short_lag, carry);
- }
- }
- eng.carry = carry;
- eng.k = k;
- }
- };
- }
- /**
- * Instantiations of @c subtract_with_carry_engine 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 IntType, std::size_t w, std::size_t s, std::size_t r>
- class subtract_with_carry_engine
- {
- public:
- typedef IntType result_type;
- BOOST_STATIC_CONSTANT(std::size_t, word_size = w);
- BOOST_STATIC_CONSTANT(std::size_t, long_lag = r);
- BOOST_STATIC_CONSTANT(std::size_t, short_lag = s);
- BOOST_STATIC_CONSTANT(uint32_t, default_seed = 19780503u);
- // Required by the old Boost.Random concepts
- BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
- // Backwards compatibility
- BOOST_STATIC_CONSTANT(result_type, modulus = (result_type(1) << w));
-
- BOOST_STATIC_ASSERT(std::numeric_limits<result_type>::is_integer);
- /**
- * Constructs a new @c subtract_with_carry_engine and seeds
- * it with the default seed.
- */
- subtract_with_carry_engine() { seed(); }
- /**
- * Constructs a new @c subtract_with_carry_engine and seeds
- * it with @c value.
- */
- BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry_engine,
- IntType, value)
- { seed(value); }
- /**
- * Constructs a new @c subtract_with_carry_engine and seeds
- * it with values produced by @c seq.generate().
- */
- BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(subtract_with_carry_engine,
- SeedSeq, seq)
- { seed(seq); }
- /**
- * Constructs a new @c subtract_with_carry_engine and seeds
- * it with values from a range. first is updated to point
- * one past the last value consumed. If there are not
- * enough elements in the range to fill the entire state of
- * the generator, throws @c std::invalid_argument.
- */
- template<class It> subtract_with_carry_engine(It& first, It last)
- { seed(first,last); }
- // compiler-generated copy ctor and assignment operator are fine
- /** Seeds the generator with the default seed. */
- void seed() { seed(default_seed); }
- BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry_engine,
- IntType, value)
- {
- typedef linear_congruential_engine<uint32_t,40014,0,2147483563> gen_t;
- gen_t intgen(static_cast<boost::uint32_t>(value == 0 ? default_seed : value));
- detail::generator_seed_seq<gen_t> gen(intgen);
- seed(gen);
- }
- /** Seeds the generator with values produced by @c seq.generate(). */
- BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(subtract_with_carry, SeedSeq, seq)
- {
- detail::seed_array_int<w>(seq, x);
- carry = (x[long_lag-1] == 0);
- k = 0;
- }
- /**
- * Seeds the generator with values from a range. Updates @c first to
- * point one past the last consumed value. If the range does not
- * contain enough elements to fill the entire state of the generator,
- * throws @c std::invalid_argument.
- */
- template<class It>
- void seed(It& first, It last)
- {
- detail::fill_array_int<w>(first, last, x);
- carry = (x[long_lag-1] == 0);
- k = 0;
- }
- /** Returns the smallest value that the generator can produce. */
- static BOOST_CONSTEXPR result_type min BOOST_PREVENT_MACRO_SUBSTITUTION ()
- { return 0; }
- /** Returns the largest value that the generator can produce. */
- static BOOST_CONSTEXPR result_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
- { return boost::low_bits_mask_t<w>::sig_bits; }
- /** Returns the next value of the generator. */
- result_type operator()()
- {
- std::size_t short_index =
- (k < short_lag)?
- (k + long_lag - short_lag) :
- (k - short_lag);
- carry = do_update(k, short_index, carry);
- IntType result = x[k];
- ++k;
- if(k >= long_lag)
- k = 0;
- return result;
- }
- /** Advances the state of the generator by @c z. */
- void discard(boost::uintmax_t z)
- {
- detail::subtract_with_carry_discard::apply(*this, z);
- }
- /** Fills a range with random values. */
- template<class It>
- void generate(It first, It last)
- { detail::generate_from_int(*this, first, last); }
-
- /** Writes a @c subtract_with_carry_engine to a @c std::ostream. */
- BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, subtract_with_carry_engine, f)
- {
- for(unsigned int j = 0; j < f.long_lag; ++j)
- os << f.compute(j) << ' ';
- os << f.carry;
- return os;
- }
- /** Reads a @c subtract_with_carry_engine from a @c std::istream. */
- BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, subtract_with_carry_engine, f)
- {
- for(unsigned int j = 0; j < f.long_lag; ++j)
- is >> f.x[j] >> std::ws;
- is >> f.carry;
- f.k = 0;
- return is;
- }
- /**
- * Returns true if the two generators will produce identical
- * sequences of values.
- */
- BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(subtract_with_carry_engine, x_, y)
- {
- for(unsigned int j = 0; j < r; ++j)
- if(x_.compute(j) != y.compute(j))
- return false;
- return true;
- }
- /**
- * Returns true if the two generators will produce different
- * sequences of values.
- */
- BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(subtract_with_carry_engine)
- private:
- /// \cond show_private
- // returns x(i-r+index), where index is in 0..r-1
- IntType compute(unsigned int index) const
- {
- return x[(k+index) % long_lag];
- }
- friend struct detail::subtract_with_carry_discard;
- IntType do_update(std::size_t current, std::size_t short_index, IntType carry_)
- {
- IntType delta;
- IntType temp = x[current] + carry_;
- if (x[short_index] >= temp) {
- // x(n) >= 0
- delta = x[short_index] - temp;
- carry_ = 0;
- } else {
- // x(n) < 0
- delta = modulus - temp + x[short_index];
- carry_ = 1;
- }
- x[current] = delta;
- return carry_;
- }
- /// \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];
- std::size_t k;
- IntType carry;
- };
- #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
- // A definition is required even for integral static constants
- template<class IntType, std::size_t w, std::size_t s, std::size_t r>
- const bool subtract_with_carry_engine<IntType, w, s, r>::has_fixed_range;
- template<class IntType, std::size_t w, std::size_t s, std::size_t r>
- const IntType subtract_with_carry_engine<IntType, w, s, r>::modulus;
- template<class IntType, std::size_t w, std::size_t s, std::size_t r>
- const std::size_t subtract_with_carry_engine<IntType, w, s, r>::word_size;
- template<class IntType, std::size_t w, std::size_t s, std::size_t r>
- const std::size_t subtract_with_carry_engine<IntType, w, s, r>::long_lag;
- template<class IntType, std::size_t w, std::size_t s, std::size_t r>
- const std::size_t subtract_with_carry_engine<IntType, w, s, r>::short_lag;
- template<class IntType, std::size_t w, std::size_t s, std::size_t r>
- const uint32_t subtract_with_carry_engine<IntType, w, s, r>::default_seed;
- #endif
- // use a floating-point representation to produce values in [0..1)
- /**
- * Instantiations of \subtract_with_carry_01_engine 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 RealType, std::size_t w, std::size_t s, std::size_t r>
- class subtract_with_carry_01_engine
- {
- public:
- typedef RealType result_type;
- BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
- BOOST_STATIC_CONSTANT(std::size_t, word_size = w);
- BOOST_STATIC_CONSTANT(std::size_t, long_lag = r);
- BOOST_STATIC_CONSTANT(std::size_t, short_lag = s);
- BOOST_STATIC_CONSTANT(boost::uint32_t, default_seed = 19780503u);
- BOOST_STATIC_ASSERT(!std::numeric_limits<result_type>::is_integer);
- /** Creates a new \subtract_with_carry_01_engine using the default seed. */
- subtract_with_carry_01_engine() { init_modulus(); seed(); }
- /** Creates a new subtract_with_carry_01_engine and seeds it with value. */
- BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry_01_engine,
- boost::uint32_t, value)
- { init_modulus(); seed(value); }
- /**
- * Creates a new \subtract_with_carry_01_engine and seeds with values
- * produced by seq.generate().
- */
- BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(subtract_with_carry_01_engine,
- SeedSeq, seq)
- { init_modulus(); seed(seq); }
- /**
- * Creates a new \subtract_with_carry_01_engine and seeds it with values
- * from a range. Advances first to point one past the last consumed
- * value. If the range does not contain enough elements to fill the
- * entire state, throws @c std::invalid_argument.
- */
- template<class It> subtract_with_carry_01_engine(It& first, It last)
- { init_modulus(); seed(first,last); }
- private:
- /// \cond show_private
- void init_modulus()
- {
- #ifndef BOOST_NO_STDC_NAMESPACE
- // allow for Koenig lookup
- using std::pow;
- #endif
- _modulus = pow(RealType(2), RealType(word_size));
- }
- /// \endcond
- public:
- // compiler-generated copy ctor and assignment operator are fine
- /** Seeds the generator with the default seed. */
- void seed() { seed(default_seed); }
- /** Seeds the generator with @c value. */
- BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry_01_engine,
- boost::uint32_t, value)
- {
- typedef linear_congruential_engine<uint32_t, 40014, 0, 2147483563> gen_t;
- gen_t intgen(value == 0 ? default_seed : value);
- detail::generator_seed_seq<gen_t> gen(intgen);
- seed(gen);
- }
- /** Seeds the generator with values produced by @c seq.generate(). */
- BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(subtract_with_carry_01_engine,
- SeedSeq, seq)
- {
- detail::seed_array_real<w>(seq, x);
- carry = (x[long_lag-1] ? result_type(0) : result_type(1 / _modulus));
- k = 0;
- }
- /**
- * Seeds the generator with values from a range. Updates first to
- * point one past the last consumed element. If there are not
- * enough elements in the range to fill the entire state, throws
- * @c std::invalid_argument.
- */
- template<class It>
- void seed(It& first, It last)
- {
- detail::fill_array_real<w>(first, last, x);
- carry = (x[long_lag-1] ? result_type(0) : result_type(1 / _modulus));
- k = 0;
- }
- /** Returns the smallest value that the generator can produce. */
- static BOOST_CONSTEXPR result_type min BOOST_PREVENT_MACRO_SUBSTITUTION ()
- { return result_type(0); }
- /** Returns the largest value that the generator can produce. */
- static BOOST_CONSTEXPR result_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
- { return result_type(1); }
- /** Returns the next value of the generator. */
- result_type operator()()
- {
- std::size_t short_index =
- (k < short_lag) ?
- (k + long_lag - short_lag) :
- (k - short_lag);
- carry = do_update(k, short_index, carry);
- RealType result = x[k];
- ++k;
- if(k >= long_lag)
- k = 0;
- return result;
- }
- /** Advances the state of the generator by @c z. */
- void discard(boost::uintmax_t z)
- { detail::subtract_with_carry_discard::apply(*this, z); }
- /** Fills a range with random values. */
- template<class Iter>
- void generate(Iter first, Iter last)
- { detail::generate_from_real(*this, first, last); }
- /** Writes a \subtract_with_carry_01_engine to a @c std::ostream. */
- BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, subtract_with_carry_01_engine, f)
- {
- 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;
- }
-
- /** Reads a \subtract_with_carry_01_engine from a @c std::istream. */
- BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, subtract_with_carry_01_engine, f)
- {
- RealType value;
- for(unsigned int j = 0; j < long_lag; ++j) {
- is >> value >> std::ws;
- f.x[j] = value / f._modulus;
- }
- is >> value;
- f.carry = value / f._modulus;
- f.k = 0;
- return is;
- }
- /** Returns true if the two generators will produce identical sequences. */
- BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(subtract_with_carry_01_engine, x_, y)
- {
- for(unsigned int j = 0; j < r; ++j)
- if(x_.compute(j) != y.compute(j))
- return false;
- return true;
- }
- /** Returns true if the two generators will produce different sequences. */
- BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(subtract_with_carry_01_engine)
- private:
- /// \cond show_private
- RealType compute(unsigned int index) const
- {
- return x[(k+index) % long_lag];
- }
- friend struct detail::subtract_with_carry_discard;
- RealType do_update(std::size_t current, std::size_t short_index, RealType carry_)
- {
- RealType delta = x[short_index] - x[current] - carry_;
- if(delta < 0) {
- delta += RealType(1);
- carry_ = RealType(1)/_modulus;
- } else {
- carry_ = 0;
- }
- x[current] = delta;
- return carry_;
- }
- /// \endcond
- std::size_t 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<class RealType, std::size_t w, std::size_t s, std::size_t r>
- const bool subtract_with_carry_01_engine<RealType, w, s, r>::has_fixed_range;
- template<class RealType, std::size_t w, std::size_t s, std::size_t r>
- const std::size_t subtract_with_carry_01_engine<RealType, w, s, r>::word_size;
- template<class RealType, std::size_t w, std::size_t s, std::size_t r>
- const std::size_t subtract_with_carry_01_engine<RealType, w, s, r>::long_lag;
- template<class RealType, std::size_t w, std::size_t s, std::size_t r>
- const std::size_t subtract_with_carry_01_engine<RealType, w, s, r>::short_lag;
- template<class RealType, std::size_t w, std::size_t s, std::size_t r>
- const uint32_t subtract_with_carry_01_engine<RealType, w, s, r>::default_seed;
- #endif
- /// \cond show_deprecated
- template<class IntType, IntType m, unsigned s, unsigned r, IntType v>
- class subtract_with_carry :
- public subtract_with_carry_engine<IntType,
- boost::static_log2<m>::value, s, r>
- {
- typedef subtract_with_carry_engine<IntType,
- boost::static_log2<m>::value, s, r> base_type;
- public:
- subtract_with_carry() {}
- BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(subtract_with_carry, Gen, gen)
- { seed(gen); }
- BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry,
- IntType, val)
- { seed(val); }
- template<class It>
- subtract_with_carry(It& first, It last) : base_type(first, last) {}
- void seed() { base_type::seed(); }
- BOOST_RANDOM_DETAIL_GENERATOR_SEED(subtract_with_carry, Gen, gen)
- {
- detail::generator_seed_seq<Gen> seq(gen);
- base_type::seed(seq);
- }
- BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry, IntType, val)
- { base_type::seed(val); }
- template<class It>
- void seed(It& first, It last) { base_type::seed(first, last); }
- };
- template<class RealType, int w, unsigned s, unsigned r, int v = 0>
- class subtract_with_carry_01 :
- public subtract_with_carry_01_engine<RealType, w, s, r>
- {
- typedef subtract_with_carry_01_engine<RealType, w, s, r> base_type;
- public:
- subtract_with_carry_01() {}
- BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(subtract_with_carry_01, Gen, gen)
- { seed(gen); }
- BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry_01,
- uint32_t, val)
- { seed(val); }
- template<class It>
- subtract_with_carry_01(It& first, It last) : base_type(first, last) {}
- void seed() { base_type::seed(); }
- BOOST_RANDOM_DETAIL_GENERATOR_SEED(subtract_with_carry_01, Gen, gen)
- {
- detail::generator_seed_seq<Gen> seq(gen);
- base_type::seed(seq);
- }
- BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry_01, uint32_t, val)
- { base_type::seed(val); }
- template<class It>
- void seed(It& first, It last) { base_type::seed(first, last); }
- };
- /// \endcond
- namespace detail {
- template<class Engine>
- struct generator_bits;
- template<class RealType, std::size_t w, std::size_t s, std::size_t r>
- struct generator_bits<subtract_with_carry_01_engine<RealType, w, s, r> > {
- static std::size_t value() { return w; }
- };
- template<class RealType, int w, unsigned s, unsigned r, int v>
- struct generator_bits<subtract_with_carry_01<RealType, w, s, r, v> > {
- static std::size_t value() { return w; }
- };
- }
- } // namespace random
- } // namespace boost
- #endif // BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP
|