Chris@16: /////////////////////////////////////////////////////////////// Chris@16: // Copyright Jens Maurer 2006-1011 Chris@16: // Copyright Steven Watanabe 2011 Chris@16: // Copyright 2012 John Maddock. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_ Chris@16: Chris@16: #ifndef BOOST_MP_RANDOM_HPP Chris@16: #define BOOST_MP_RANDOM_HPP Chris@16: Chris@16: #ifdef BOOST_MSVC Chris@16: #pragma warning(push) Chris@16: #pragma warning(disable:4127) Chris@16: #endif Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost{ namespace random{ namespace detail{ Chris@16: // Chris@16: // This is a horrible hack: this declaration has to appear before the definition of Chris@16: // uniform_int_distribution, otherwise it won't be used... Chris@16: // Need to find a better solution, like make Boost.Random safe to use with Chris@16: // UDT's and depricate/remove this header altogether. Chris@16: // Chris@16: template Chris@16: boost::multiprecision::number Chris@16: generate_uniform_int(Engine& eng, const boost::multiprecision::number& min_value, const boost::multiprecision::number& max_value); Chris@16: Chris@16: }}} Chris@16: Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost{ Chris@16: namespace random{ Chris@16: namespace detail{ Chris@16: Chris@16: template Chris@16: struct subtract, true> Chris@16: { Chris@16: typedef boost::multiprecision::number result_type; Chris@16: result_type operator()(result_type const& x, result_type const& y) { return x - y; } Chris@16: }; Chris@16: Chris@16: } Chris@16: Chris@16: template Chris@16: class independent_bits_engine > Chris@16: { Chris@16: public: Chris@16: typedef Engine base_type; Chris@16: typedef boost::multiprecision::number result_type; Chris@16: Chris@16: static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () Chris@16: { return 0; } Chris@16: // This is the only function we modify compared to the primary template: Chris@16: static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () Chris@16: { Chris@16: // This expression allows for the possibility that w == std::numeric_limits::digits: Chris@16: return (((result_type(1) << (w - 1)) - 1) << 1) + 1; Chris@16: } Chris@16: Chris@16: independent_bits_engine() { } Chris@16: Chris@16: BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(independent_bits_engine, Chris@16: result_type, seed_arg) Chris@16: { Chris@16: _base.seed(seed_arg); Chris@16: } Chris@16: Chris@16: BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(independent_bits_engine, Chris@16: SeedSeq, seq) Chris@16: { _base.seed(seq); } Chris@16: Chris@16: independent_bits_engine(const base_type& base_arg) : _base(base_arg) {} Chris@16: Chris@16: template Chris@16: independent_bits_engine(It& first, It last) : _base(first, last) { } Chris@16: Chris@16: void seed() { _base.seed(); } Chris@16: Chris@16: BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(independent_bits_engine, Chris@16: result_type, seed_arg) Chris@16: { _base.seed(seed_arg); } Chris@16: Chris@16: BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(independent_bits_engine, Chris@16: SeedSeq, seq) Chris@16: { _base.seed(seq); } Chris@16: Chris@16: template void seed(It& first, It last) Chris@16: { _base.seed(first, last); } Chris@16: Chris@16: result_type operator()() Chris@16: { Chris@16: // While it may seem wasteful to recalculate this Chris@16: // every time, both msvc and gcc can propagate Chris@16: // constants, resolving this at compile time. Chris@16: base_unsigned range = Chris@16: detail::subtract()((_base.max)(), (_base.min)()); Chris@16: std::size_t m = Chris@16: (range == (std::numeric_limits::max)()) ? Chris@16: std::numeric_limits::digits : Chris@16: detail::integer_log2(range + 1); Chris@16: std::size_t n = (w + m - 1) / m; Chris@16: std::size_t w0, n0; Chris@16: base_unsigned y0, y1; Chris@16: base_unsigned y0_mask, y1_mask; Chris@16: calc_params(n, range, w0, n0, y0, y1, y0_mask, y1_mask); Chris@16: if(base_unsigned(range - y0 + 1) > y0 / n) { Chris@16: // increment n and try again. Chris@16: ++n; Chris@16: calc_params(n, range, w0, n0, y0, y1, y0_mask, y1_mask); Chris@16: } Chris@16: Chris@16: BOOST_ASSERT(n0*w0 + (n - n0)*(w0 + 1) == w); Chris@16: Chris@16: result_type S = 0; Chris@16: for(std::size_t k = 0; k < n0; ++k) { Chris@16: base_unsigned u; Chris@16: do { Chris@16: u = detail::subtract()(_base(), (_base.min)()); Chris@16: } while(u > base_unsigned(y0 - 1)); Chris@16: S = (S << w0) + (u & y0_mask); Chris@16: } Chris@16: for(std::size_t k = 0; k < (n - n0); ++k) { Chris@16: base_unsigned u; Chris@16: do { Chris@16: u = detail::subtract()(_base(), (_base.min)()); Chris@16: } while(u > base_unsigned(y1 - 1)); Chris@16: S = (S << (w0 + 1)) + (u & y1_mask); Chris@16: } Chris@16: return S; 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 i = 0; i < z; ++i) { Chris@16: (*this)(); Chris@16: } Chris@16: } Chris@16: Chris@16: const base_type& base() const { return _base; } Chris@16: Chris@16: /** Chris@16: * Writes the textual representation if the generator to a @c std::ostream. Chris@16: * The textual representation of the engine is the textual representation Chris@16: * of the base engine. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, independent_bits_engine, r) Chris@16: { Chris@16: os << r._base; Chris@16: return os; Chris@16: } Chris@16: Chris@16: /** Chris@16: * Reads the state of an @c independent_bits_engine from a Chris@16: * @c std::istream. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, independent_bits_engine, r) Chris@16: { Chris@16: is >> r._base; Chris@16: return is; Chris@16: } Chris@16: Chris@16: /** Chris@16: * Returns: true iff the two @c independent_bits_engines will Chris@16: * produce the same sequence of values. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(independent_bits_engine, x, y) Chris@16: { return x._base == y._base; } Chris@16: /** Chris@16: * Returns: true iff the two @c independent_bits_engines will Chris@16: * produce different sequences of values. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(independent_bits_engine) Chris@16: Chris@16: private: Chris@16: Chris@16: /// \cond show_private Chris@16: typedef typename base_type::result_type base_result; Chris@16: typedef typename make_unsigned::type base_unsigned; Chris@16: Chris@16: void calc_params( Chris@16: std::size_t n, base_unsigned range, Chris@16: std::size_t& w0, std::size_t& n0, Chris@16: base_unsigned& y0, base_unsigned& y1, Chris@16: base_unsigned& y0_mask, base_unsigned& y1_mask) Chris@16: { Chris@16: BOOST_ASSERT(w >= n); Chris@16: w0 = w/n; Chris@16: n0 = n - w % n; Chris@16: y0_mask = (base_unsigned(2) << (w0 - 1)) - 1; Chris@16: y1_mask = (y0_mask << 1) | 1; Chris@16: y0 = (range + 1) & ~y0_mask; Chris@16: y1 = (range + 1) & ~y1_mask; Chris@16: BOOST_ASSERT(y0 != 0 || base_unsigned(range + 1) == 0); Chris@16: } Chris@16: /// \endcond Chris@16: Chris@16: Engine _base; Chris@16: }; Chris@16: Chris@16: template Chris@16: class uniform_smallint > Chris@16: { Chris@16: public: Chris@16: typedef boost::multiprecision::number input_type; Chris@16: typedef boost::multiprecision::number result_type; Chris@16: Chris@16: class param_type Chris@16: { Chris@16: public: Chris@16: Chris@16: typedef uniform_smallint distribution_type; Chris@16: Chris@16: /** constructs the parameters of a @c uniform_smallint distribution. */ Chris@16: param_type(result_type const& min_arg = 0, result_type const& max_arg = 9) Chris@16: : _min(min_arg), _max(max_arg) Chris@16: { Chris@16: BOOST_ASSERT(_min <= _max); Chris@16: } Chris@16: Chris@16: /** Returns the minimum value. */ Chris@16: result_type a() const { return _min; } Chris@16: /** Returns the maximum value. */ Chris@16: result_type b() const { return _max; } Chris@16: Chris@16: Chris@16: /** Writes the parameters to a @c std::ostream. */ Chris@16: BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) Chris@16: { Chris@16: os << parm._min << " " << parm._max; Chris@16: return os; Chris@16: } Chris@16: Chris@16: /** Reads the parameters from a @c std::istream. */ Chris@16: BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) Chris@16: { Chris@16: is >> parm._min >> std::ws >> parm._max; Chris@16: return is; Chris@16: } Chris@16: Chris@16: /** Returns true if the two sets of parameters are equal. */ Chris@16: BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) Chris@16: { return lhs._min == rhs._min && lhs._max == rhs._max; } Chris@16: Chris@16: /** Returns true if the two sets of parameters are different. */ Chris@16: BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) Chris@16: Chris@16: private: Chris@16: result_type _min; Chris@16: result_type _max; Chris@16: }; Chris@16: Chris@16: /** Chris@16: * Constructs a @c uniform_smallint. @c min and @c max are the Chris@16: * lower and upper bounds of the output range, respectively. Chris@16: */ Chris@16: explicit uniform_smallint(result_type const& min_arg = 0, result_type const& max_arg = 9) Chris@16: : _min(min_arg), _max(max_arg) {} Chris@16: Chris@16: /** Chris@16: * Constructs a @c uniform_smallint from its parameters. Chris@16: */ Chris@16: explicit uniform_smallint(const param_type& parm) Chris@16: : _min(parm.a()), _max(parm.b()) {} Chris@16: Chris@16: /** Returns the minimum value of the distribution. */ Chris@16: result_type a() const { return _min; } Chris@16: /** Returns the maximum value of the distribution. */ Chris@16: result_type b() const { return _max; } Chris@16: /** Returns the minimum value of the distribution. */ Chris@16: result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _min; } Chris@16: /** Returns the maximum value of the distribution. */ Chris@16: result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _max; } Chris@16: Chris@16: /** Returns the parameters of the distribution. */ Chris@16: param_type param() const { return param_type(_min, _max); } Chris@16: /** Sets the parameters of the distribution. */ Chris@16: void param(const param_type& parm) Chris@16: { Chris@16: _min = parm.a(); Chris@16: _max = parm.b(); Chris@16: } Chris@16: Chris@16: /** Chris@16: * Effects: Subsequent uses of the distribution do not depend Chris@16: * on values produced by any engine prior to invoking reset. Chris@16: */ Chris@16: void reset() { } Chris@16: Chris@16: /** Returns a value uniformly distributed in the range [min(), max()]. */ Chris@16: template Chris@16: result_type operator()(Engine& eng) const Chris@16: { Chris@16: typedef typename Engine::result_type base_result; Chris@16: return generate(eng, boost::is_integral()); Chris@16: } Chris@16: Chris@16: /** Returns a value uniformly distributed in the range [param.a(), param.b()]. */ Chris@16: template Chris@16: result_type operator()(Engine& eng, const param_type& parm) const Chris@16: { return uniform_smallint(parm)(eng); } Chris@16: Chris@16: /** Writes the distribution to a @c std::ostream. */ Chris@16: BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, uniform_smallint, ud) Chris@16: { Chris@16: os << ud._min << " " << ud._max; Chris@16: return os; Chris@16: } Chris@16: Chris@16: /** Reads the distribution from a @c std::istream. */ Chris@16: BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, uniform_smallint, ud) Chris@16: { Chris@16: is >> ud._min >> std::ws >> ud._max; Chris@16: return is; Chris@16: } Chris@16: Chris@16: /** Chris@16: * Returns true if the two distributions will produce identical Chris@16: * sequences of values given equal generators. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(uniform_smallint, lhs, rhs) Chris@16: { return lhs._min == rhs._min && lhs._max == rhs._max; } Chris@16: Chris@16: /** Chris@16: * Returns true if the two distributions may produce different Chris@16: * sequences of values given equal generators. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(uniform_smallint) Chris@16: Chris@16: private: Chris@16: Chris@16: // \cond show_private Chris@16: template Chris@16: result_type generate(Engine& eng, boost::mpl::true_) const Chris@16: { Chris@16: // equivalent to (eng() - eng.min()) % (_max - _min + 1) + _min, Chris@16: // but guarantees no overflow. Chris@16: typedef typename Engine::result_type base_result; Chris@16: typedef typename boost::make_unsigned::type base_unsigned; Chris@16: typedef result_type range_type; Chris@16: range_type range = random::detail::subtract()(_max, _min); Chris@16: base_unsigned base_range = Chris@16: random::detail::subtract()((eng.max)(), (eng.min)()); Chris@16: base_unsigned val = Chris@16: random::detail::subtract()(eng(), (eng.min)()); Chris@16: if(range >= base_range) { Chris@16: return boost::random::detail::add()( Chris@16: static_cast(val), _min); Chris@16: } else { Chris@16: base_unsigned modulus = static_cast(range) + 1; Chris@16: return boost::random::detail::add()( Chris@16: static_cast(val % modulus), _min); Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: result_type generate(Engine& eng, boost::mpl::false_) const Chris@16: { Chris@16: typedef typename Engine::result_type base_result; Chris@16: typedef result_type range_type; Chris@16: range_type range = random::detail::subtract()(_max, _min); Chris@16: base_result val = boost::uniform_01()(eng); Chris@16: // what is the worst that can possibly happen here? Chris@16: // base_result may not be able to represent all the values in [0, range] Chris@16: // exactly. If this happens, it will cause round off error and we Chris@16: // won't be able to produce all the values in the range. We don't Chris@16: // care about this because the user has already told us not to by Chris@16: // using uniform_smallint. However, we do need to be careful Chris@16: // to clamp the result, or floating point rounding can produce Chris@16: // an out of range result. Chris@16: range_type offset = static_cast(val * (range + 1)); Chris@16: if(offset > range) return _max; Chris@16: return boost::random::detail::add()(offset , _min); Chris@16: } Chris@16: // \endcond Chris@16: Chris@16: result_type _min; Chris@16: result_type _max; Chris@16: }; Chris@16: Chris@16: Chris@16: namespace detail{ Chris@16: Chris@16: template Chris@16: struct select_uniform_01 > Chris@16: { Chris@16: template Chris@16: struct apply Chris@16: { Chris@16: typedef new_uniform_01 > type; Chris@16: }; Chris@16: }; Chris@16: Chris@16: template Chris@16: boost::multiprecision::number Chris@16: generate_uniform_int( Chris@16: Engine& eng, const boost::multiprecision::number& min_value, const boost::multiprecision::number& max_value, Chris@16: boost::mpl::true_ /** is_integral */) Chris@16: { Chris@16: typedef boost::multiprecision::number result_type; Chris@16: // Since we're using big-numbers, use the result type for all internal calculations: Chris@16: typedef result_type range_type; Chris@16: typedef result_type base_result; Chris@16: typedef result_type base_unsigned; Chris@16: const range_type range = random::detail::subtract()(max_value, min_value); Chris@16: const base_result bmin = (eng.min)(); Chris@16: const base_unsigned brange = Chris@16: random::detail::subtract()((eng.max)(), (eng.min)()); Chris@16: Chris@16: if(range == 0) { Chris@16: return min_value; Chris@16: } else if(brange == range) { Chris@16: // this will probably never happen in real life Chris@16: // basically nothing to do; just take care we don't overflow / underflow Chris@16: base_unsigned v = random::detail::subtract()(eng(), bmin); Chris@16: return random::detail::add()(v, min_value); Chris@16: } else if(brange < range) { Chris@16: // use rejection method to handle things like 0..3 --> 0..4 Chris@16: for(;;) { Chris@16: // concatenate several invocations of the base RNG Chris@16: // take extra care to avoid overflows Chris@16: Chris@16: // limit == floor((range+1)/(brange+1)) Chris@16: // Therefore limit*(brange+1) <= range+1 Chris@16: range_type limit; Chris@16: if(std::numeric_limits::is_bounded && (range == (std::numeric_limits::max)())) { Chris@16: limit = range/(range_type(brange)+1); Chris@16: if(range % (range_type(brange)+1) == range_type(brange)) Chris@16: ++limit; Chris@16: } else { Chris@16: limit = (range+1)/(range_type(brange)+1); Chris@16: } Chris@16: Chris@16: // We consider "result" as expressed to base (brange+1): Chris@16: // For every power of (brange+1), we determine a random factor Chris@16: range_type result = range_type(0); Chris@16: range_type mult = range_type(1); Chris@16: Chris@16: // loop invariants: Chris@16: // result < mult Chris@16: // mult <= range Chris@16: while(mult <= limit) { Chris@16: // Postcondition: result <= range, thus no overflow Chris@16: // Chris@16: // limit*(brange+1)<=range+1 def. of limit (1) Chris@16: // eng()-bmin<=brange eng() post. (2) Chris@16: // and mult<=limit. loop condition (3) Chris@16: // Therefore mult*(eng()-bmin+1)<=range+1 by (1),(2),(3) (4) Chris@16: // Therefore mult*(eng()-bmin)+mult<=range+1 rearranging (4) (5) Chris@16: // result(random::detail::subtract()(eng(), bmin) * mult); Chris@16: Chris@16: // equivalent to (mult * (brange+1)) == range+1, but avoids overflow. Chris@16: if(mult * range_type(brange) == range - mult + 1) { Chris@16: // The destination range is an integer power of Chris@16: // the generator's range. Chris@16: return(result); Chris@16: } Chris@16: Chris@16: // Postcondition: mult <= range Chris@16: // Chris@16: // limit*(brange+1)<=range+1 def. of limit (1) Chris@16: // mult<=limit loop condition (2) Chris@16: // Therefore mult*(brange+1)<=range+1 by (1), (2) (3) Chris@16: // mult*(brange+1)!=range+1 preceding if (4) Chris@16: // Therefore mult*(brange+1) limit loop condition (1) Chris@16: // Suppose range/mult >= brange+1 Assumption (2) Chris@16: // range >= mult*(brange+1) by (2) (3) Chris@16: // range+1 > mult*(brange+1) by (3) (4) Chris@16: // range+1 > (limit+1)*(brange+1) by (1), (4) (5) Chris@16: // (range+1)/(brange+1) > limit+1 by (5) (6) Chris@16: // limit < floor((range+1)/(brange+1)) by (6) (7) Chris@16: // limit==floor((range+1)/(brange+1)) def. of limit (8) Chris@16: // not (2) reductio (9) Chris@16: // Chris@16: // loop postcondition: (range/mult)*mult+(mult-1) >= range Chris@16: // Chris@16: // (range/mult)*mult + range%mult == range identity (1) Chris@16: // range%mult < mult def. of % (2) Chris@16: // (range/mult)*mult+mult > range by (1), (2) (3) Chris@16: // (range/mult)*mult+(mult-1) >= range by (3) (4) Chris@16: // Chris@16: // Note that the maximum value of result at this point is (mult-1), Chris@16: // so after this final step, we generate numbers that can be Chris@16: // at least as large as range. We have to really careful to avoid Chris@16: // overflow in this final addition and in the rejection. Anything Chris@16: // that overflows is larger than range and can thus be rejected. Chris@16: Chris@16: // range/mult < brange+1 -> no endless loop Chris@16: range_type result_increment = Chris@16: generate_uniform_int( Chris@16: eng, Chris@16: static_cast(0), Chris@16: static_cast(range/mult), Chris@16: boost::mpl::true_()); Chris@16: if(std::numeric_limits::is_bounded && ((std::numeric_limits::max)() / mult < result_increment)) { Chris@16: // The multiplication would overflow. Reject immediately. Chris@16: continue; Chris@16: } Chris@16: result_increment *= mult; Chris@16: // unsigned integers are guaranteed to wrap on overflow. Chris@16: result += result_increment; Chris@16: if(result < result_increment) { Chris@16: // The addition overflowed. Reject. Chris@16: continue; Chris@16: } Chris@16: if(result > range) { Chris@16: // Too big. Reject. Chris@16: continue; Chris@16: } Chris@16: return random::detail::add()(result, min_value); Chris@16: } Chris@16: } else { // brange > range Chris@16: range_type bucket_size; Chris@16: // it's safe to add 1 to range, as long as we cast it first, Chris@16: // because we know that it is less than brange. However, Chris@16: // we do need to be careful not to cause overflow by adding 1 Chris@16: // to brange. Chris@16: if(std::numeric_limits::is_bounded && (brange == (std::numeric_limits::max)())) { Chris@16: bucket_size = brange / (range+1); Chris@16: if(brange % (range+1) == range) { Chris@16: ++bucket_size; Chris@16: } Chris@16: } else { Chris@16: bucket_size = (brange+1) / (range+1); Chris@16: } Chris@16: for(;;) { Chris@16: range_type result = Chris@16: random::detail::subtract()(eng(), bmin); Chris@16: result /= bucket_size; Chris@16: // result and range are non-negative, and result is possibly larger Chris@16: // than range, so the cast is safe Chris@16: if(result <= range) Chris@16: return result + min_value; Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: inline boost::multiprecision::number Chris@16: generate_uniform_int(Engine& eng, const boost::multiprecision::number& min_value, const boost::multiprecision::number& max_value) Chris@16: { Chris@16: typedef typename Engine::result_type base_result; Chris@16: typedef typename mpl::or_, mpl::bool_::value == boost::multiprecision::number_kind_integer> >::type tag_type; Chris@16: return generate_uniform_int(eng, min_value, max_value, Chris@16: tag_type()); Chris@16: } Chris@16: Chris@101: template Chris@101: inline boost::multiprecision::number generate_uniform_real(Engine& eng, const boost::multiprecision::number& min_value, const boost::multiprecision::number& max_value) Chris@101: { Chris@101: if(max_value / 2 - min_value / 2 > (std::numeric_limits >::max)() / 2) Chris@101: return 2 * generate_uniform_real(eng, boost::multiprecision::number(min_value / 2), boost::multiprecision::number(max_value / 2)); Chris@101: typedef typename Engine::result_type base_result; Chris@101: return generate_uniform_real(eng, min_value, max_value, Chris@101: boost::is_integral()); Chris@101: } Chris@101: Chris@16: } // detail Chris@16: Chris@16: Chris@16: }} // namespaces Chris@16: Chris@16: #ifdef BOOST_MSVC Chris@16: #pragma warning(pop) Chris@16: #endif Chris@16: Chris@16: #endif