Chris@16: /* boost random/inversive_congruential.hpp header file Chris@16: * Chris@16: * Copyright Jens Maurer 2000-2001 Chris@16: * Distributed under the Boost Software License, Version 1.0. (See Chris@16: * accompanying file LICENSE_1_0.txt or copy at Chris@16: * http://www.boost.org/LICENSE_1_0.txt) Chris@16: * Chris@16: * See http://www.boost.org for most recent version including documentation. Chris@16: * Chris@101: * $Id$ Chris@16: * Chris@16: * Revision history Chris@16: * 2001-02-18 moved to individual header files Chris@16: */ Chris@16: Chris@16: #ifndef BOOST_RANDOM_INVERSIVE_CONGRUENTIAL_HPP Chris@16: #define BOOST_RANDOM_INVERSIVE_CONGRUENTIAL_HPP Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: namespace random { Chris@16: Chris@16: // Eichenauer and Lehn 1986 Chris@16: /** Chris@16: * Instantiations of class template @c inversive_congruential_engine model a Chris@16: * \pseudo_random_number_generator. It uses the inversive congruential Chris@16: * algorithm (ICG) described in Chris@16: * Chris@16: * @blockquote Chris@16: * "Inversive pseudorandom number generators: concepts, results and links", Chris@16: * Peter Hellekalek, In: "Proceedings of the 1995 Winter Simulation Chris@16: * Conference", C. Alexopoulos, K. Kang, W.R. Lilegdon, and D. Goldsman Chris@16: * (editors), 1995, pp. 255-262. ftp://random.mat.sbg.ac.at/pub/data/wsc95.ps Chris@16: * @endblockquote Chris@16: * Chris@16: * The output sequence is defined by x(n+1) = (a*inv(x(n)) - b) (mod p), Chris@16: * where x(0), a, b, and the prime number p are parameters of the generator. Chris@16: * The expression inv(k) denotes the multiplicative inverse of k in the Chris@16: * field of integer numbers modulo p, with inv(0) := 0. Chris@16: * Chris@16: * The template parameter IntType shall denote a signed integral type large Chris@16: * enough to hold p; a, b, and p are the parameters of the generators. The Chris@16: * template parameter val is the validation value checked by validation. Chris@16: * Chris@16: * @xmlnote Chris@16: * The implementation currently uses the Euclidian Algorithm to compute Chris@16: * the multiplicative inverse. Therefore, the inversive generators are about Chris@16: * 10-20 times slower than the others (see section"performance"). However, Chris@16: * the paper talks of only 3x slowdown, so the Euclidian Algorithm is probably Chris@16: * not optimal for calculating the multiplicative inverse. Chris@16: * @endxmlnote Chris@16: */ Chris@16: template Chris@16: class inversive_congruential_engine Chris@16: { Chris@16: public: Chris@16: typedef IntType result_type; Chris@16: BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); Chris@16: Chris@16: BOOST_STATIC_CONSTANT(result_type, multiplier = a); Chris@16: BOOST_STATIC_CONSTANT(result_type, increment = b); Chris@16: BOOST_STATIC_CONSTANT(result_type, modulus = p); Chris@16: BOOST_STATIC_CONSTANT(IntType, default_seed = 1); Chris@16: Chris@16: static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () { return b == 0 ? 1 : 0; } Chris@16: static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () { return p-1; } Chris@16: Chris@16: /** Chris@16: * Constructs an @c inversive_congruential_engine, seeding it with Chris@16: * the default seed. Chris@16: */ Chris@16: inversive_congruential_engine() { seed(); } Chris@16: Chris@16: /** Chris@16: * Constructs an @c inversive_congruential_engine, seeding it with @c x0. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(inversive_congruential_engine, Chris@16: IntType, x0) Chris@16: { seed(x0); } Chris@16: Chris@16: /** Chris@16: * Constructs an @c inversive_congruential_engine, seeding it with values Chris@16: * produced by a call to @c seq.generate(). Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(inversive_congruential_engine, Chris@16: SeedSeq, seq) Chris@16: { seed(seq); } Chris@16: Chris@16: /** Chris@16: * Constructs an @c inversive_congruential_engine, seeds it Chris@16: * with values taken from the itrator range [first, last), Chris@16: * and adjusts first to point to the element after the last one Chris@16: * used. If there are not enough elements, throws @c std::invalid_argument. Chris@16: * Chris@16: * first and last must be input iterators. Chris@16: */ Chris@16: template inversive_congruential_engine(It& first, It last) Chris@16: { seed(first, last); } Chris@16: Chris@16: /** Chris@16: * Calls seed(default_seed) Chris@16: */ Chris@16: void seed() { seed(default_seed); } Chris@16: Chris@16: /** Chris@16: * If c mod m is zero and x0 mod m is zero, changes the current value of Chris@16: * the generator to 1. Otherwise, changes it to x0 mod m. If c is zero, Chris@16: * distinct seeds in the range [1,m) will leave the generator in distinct Chris@16: * states. If c is not zero, the range is [0,m). Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(inversive_congruential_engine, IntType, x0) Chris@16: { Chris@16: // wrap _x if it doesn't fit in the destination Chris@16: if(modulus == 0) { Chris@16: _value = x0; Chris@16: } else { Chris@16: _value = x0 % modulus; Chris@16: } Chris@16: // handle negative seeds Chris@16: if(_value <= 0 && _value != 0) { Chris@16: _value += modulus; Chris@16: } Chris@16: // adjust to the correct range Chris@16: if(increment == 0 && _value == 0) { Chris@16: _value = 1; Chris@16: } Chris@16: BOOST_ASSERT(_value >= (min)()); Chris@16: BOOST_ASSERT(_value <= (max)()); Chris@16: } Chris@16: Chris@16: /** Chris@16: * Seeds an @c inversive_congruential_engine using values from a SeedSeq. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(inversive_congruential_engine, SeedSeq, seq) Chris@16: { seed(detail::seed_one_int(seq)); } Chris@16: Chris@16: /** Chris@16: * seeds an @c inversive_congruential_engine with values taken Chris@16: * from the itrator range [first, last) and adjusts @c first to Chris@16: * point to the element after the last one used. If there are Chris@16: * not enough elements, throws @c std::invalid_argument. Chris@16: * Chris@16: * @c first and @c last must be input iterators. Chris@16: */ Chris@16: template void seed(It& first, It last) Chris@16: { seed(detail::get_one_int(first, last)); } Chris@16: Chris@16: /** Returns the next output of the generator. */ Chris@16: IntType operator()() Chris@16: { Chris@16: typedef const_mod do_mod; Chris@16: _value = do_mod::mult_add(a, do_mod::invert(_value), b); Chris@16: return _value; Chris@16: } Chris@16: Chris@16: /** Fills a range with random values */ Chris@16: template Chris@16: void generate(Iter first, Iter last) Chris@16: { detail::generate_from_int(*this, first, last); } Chris@16: Chris@16: /** Advances the state of the generator by @c z. */ Chris@16: void discard(boost::uintmax_t z) Chris@16: { Chris@16: for(boost::uintmax_t j = 0; j < z; ++j) { Chris@16: (*this)(); Chris@16: } Chris@16: } Chris@16: Chris@16: /** Chris@16: * Writes the textual representation of the generator to a @c std::ostream. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, inversive_congruential_engine, x) Chris@16: { Chris@16: os << x._value; Chris@16: return os; Chris@16: } Chris@16: Chris@16: /** Chris@16: * Reads the textual representation of the generator from a @c std::istream. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, inversive_congruential_engine, x) Chris@16: { Chris@16: is >> x._value; Chris@16: return is; Chris@16: } Chris@16: Chris@16: /** Chris@16: * Returns true if the two generators will produce identical Chris@16: * sequences of outputs. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(inversive_congruential_engine, x, y) Chris@16: { return x._value == y._value; } Chris@16: Chris@16: /** Chris@16: * Returns true if the two generators will produce different Chris@16: * sequences of outputs. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(inversive_congruential_engine) Chris@16: Chris@16: private: Chris@16: IntType _value; Chris@16: }; Chris@16: Chris@16: #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION Chris@16: // A definition is required even for integral static constants Chris@16: template Chris@16: const bool inversive_congruential_engine::has_fixed_range; Chris@16: template Chris@16: const typename inversive_congruential_engine::result_type inversive_congruential_engine::multiplier; Chris@16: template Chris@16: const typename inversive_congruential_engine::result_type inversive_congruential_engine::increment; Chris@16: template Chris@16: const typename inversive_congruential_engine::result_type inversive_congruential_engine::modulus; Chris@16: template Chris@16: const typename inversive_congruential_engine::result_type inversive_congruential_engine::default_seed; Chris@16: #endif Chris@16: Chris@16: /// \cond show_deprecated Chris@16: Chris@16: // provided for backwards compatibility Chris@16: template Chris@16: class inversive_congruential : public inversive_congruential_engine Chris@16: { Chris@16: typedef inversive_congruential_engine base_type; Chris@16: public: Chris@16: inversive_congruential(IntType x0 = 1) : base_type(x0) {} Chris@16: template Chris@16: inversive_congruential(It& first, It last) : base_type(first, last) {} Chris@16: }; Chris@16: Chris@16: /// \endcond Chris@16: Chris@16: /** Chris@16: * The specialization hellekalek1995 was suggested in Chris@16: * Chris@16: * @blockquote Chris@16: * "Inversive pseudorandom number generators: concepts, results and links", Chris@16: * Peter Hellekalek, In: "Proceedings of the 1995 Winter Simulation Chris@16: * Conference", C. Alexopoulos, K. Kang, W.R. Lilegdon, and D. Goldsman Chris@16: * (editors), 1995, pp. 255-262. ftp://random.mat.sbg.ac.at/pub/data/wsc95.ps Chris@16: * @endblockquote Chris@16: */ Chris@16: typedef inversive_congruential_engine hellekalek1995; Chris@16: Chris@16: } // namespace random Chris@16: Chris@16: using random::hellekalek1995; Chris@16: Chris@16: } // namespace boost Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // BOOST_RANDOM_INVERSIVE_CONGRUENTIAL_HPP