1 /* boost random/independent_bits.hpp header file 2 * 3 * Copyright Steven Watanabe 2011 4 * Distributed under the Boost Software License, Version 1.0. (See 5 * accompanying file LICENSE_1_0.txt or copy at 6 * http://www.boost.org/LICENSE_1_0.txt) 7 * 8 * See http://www.boost.org for most recent version including documentation. 9 * 10 * $Id$ 11 * 12 */ 13 14 #ifndef BOOST_RANDOM_INDEPENDENT_BITS_HPP 15 #define BOOST_RANDOM_INDEPENDENT_BITS_HPP 16 17 #include <istream> 18 #include <iosfwd> 19 #include <boost/assert.hpp> 20 #include <boost/limits.hpp> 21 #include <boost/config.hpp> 22 #include <boost/cstdint.hpp> 23 #include <boost/integer/integer_mask.hpp> 24 #include <boost/type_traits/make_unsigned.hpp> 25 #include <boost/random/detail/config.hpp> 26 #include <boost/random/detail/integer_log2.hpp> 27 #include <boost/random/detail/operators.hpp> 28 #include <boost/random/detail/seed.hpp> 29 #include <boost/random/detail/seed_impl.hpp> 30 #include <boost/random/detail/signed_unsigned_tools.hpp> 31 32 namespace boost { 33 namespace random { 34 35 /** 36 * An instantiation of class template @c independent_bits_engine 37 * model a \pseudo_random_number_generator. It generates random 38 * numbers distributed between [0, 2^w) by combining one or 39 * more invocations of the base engine. 40 * 41 * Requires: 0 < w <= std::numeric_limits<UIntType>::digits 42 */ 43 template<class Engine, std::size_t w, class UIntType> 44 class independent_bits_engine 45 { 46 public: 47 typedef Engine base_type; 48 typedef UIntType result_type; 49 50 // Required by old Boost.Random concept 51 BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); 52 53 /** Returns the smallest value that the generator can produce. */ BOOST_PREVENT_MACRO_SUBSTITUTION()54 static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () 55 { return 0; } 56 /** Returns the largest value that the generator can produce. */ BOOST_PREVENT_MACRO_SUBSTITUTION()57 static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () 58 { return boost::low_bits_mask_t<w>::sig_bits; } 59 60 /** 61 * Constructs an @c independent_bits_engine using the 62 * default constructor of the base generator. 63 */ independent_bits_engine()64 independent_bits_engine() { } 65 66 /** 67 * Constructs an @c independent_bits_engine, using seed as 68 * the constructor argument for both base generators. 69 */ BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(independent_bits_engine,result_type,seed_arg)70 BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(independent_bits_engine, 71 result_type, seed_arg) 72 { 73 _base.seed(seed_arg); 74 } 75 76 /** 77 * Constructs an @c independent_bits_engine, using seq as 78 * the constructor argument for the base generator. 79 */ BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(independent_bits_engine,SeedSeq,seq)80 BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(independent_bits_engine, 81 SeedSeq, seq) 82 { _base.seed(seq); } 83 84 /** Constructs an @c independent_bits_engine by copying @c base. */ independent_bits_engine(const base_type & base_arg)85 independent_bits_engine(const base_type& base_arg) : _base(base_arg) {} 86 87 /** 88 * Contructs an @c independent_bits_engine with 89 * values from the range defined by the input iterators first 90 * and last. first will be modified to point to the element 91 * after the last one used. 92 * 93 * Throws: @c std::invalid_argument if the input range is too small. 94 * 95 * Exception Safety: Basic 96 */ 97 template<class It> independent_bits_engine(It & first,It last)98 independent_bits_engine(It& first, It last) : _base(first, last) { } 99 100 /** 101 * Seeds an @c independent_bits_engine using the default 102 * seed of the base generator. 103 */ seed()104 void seed() { _base.seed(); } 105 106 /** 107 * Seeds an @c independent_bits_engine, using @c seed as the 108 * seed for the base generator. 109 */ BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(independent_bits_engine,result_type,seed_arg)110 BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(independent_bits_engine, 111 result_type, seed_arg) 112 { _base.seed(seed_arg); } 113 114 /** 115 * Seeds an @c independent_bits_engine, using @c seq to 116 * seed the base generator. 117 */ BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(independent_bits_engine,SeedSeq,seq)118 BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(independent_bits_engine, 119 SeedSeq, seq) 120 { _base.seed(seq); } 121 122 /** 123 * Seeds an @c independent_bits_engine with 124 * values from the range defined by the input iterators first 125 * and last. first will be modified to point to the element 126 * after the last one used. 127 * 128 * Throws: @c std::invalid_argument if the input range is too small. 129 * 130 * Exception Safety: Basic 131 */ seed(It & first,It last)132 template<class It> void seed(It& first, It last) 133 { _base.seed(first, last); } 134 135 /** Returns the next value of the generator. */ operator ()()136 result_type operator()() 137 { 138 // While it may seem wasteful to recalculate this 139 // every time, both msvc and gcc can propagate 140 // constants, resolving this at compile time. 141 base_unsigned range = 142 detail::subtract<base_result>()((_base.max)(), (_base.min)()); 143 std::size_t m = 144 (range == (std::numeric_limits<base_unsigned>::max)()) ? 145 std::numeric_limits<base_unsigned>::digits : 146 detail::integer_log2(range + 1); 147 std::size_t n = (w + m - 1) / m; 148 std::size_t w0, n0; 149 base_unsigned y0, y1; 150 base_unsigned y0_mask, y1_mask; 151 calc_params(n, range, w0, n0, y0, y1, y0_mask, y1_mask); 152 if(base_unsigned(range - y0 + 1) > y0 / n) { 153 // increment n and try again. 154 ++n; 155 calc_params(n, range, w0, n0, y0, y1, y0_mask, y1_mask); 156 } 157 158 BOOST_ASSERT(n0*w0 + (n - n0)*(w0 + 1) == w); 159 160 result_type S = 0; 161 for(std::size_t k = 0; k < n0; ++k) { 162 base_unsigned u; 163 do { 164 u = detail::subtract<base_result>()(_base(), (_base.min)()); 165 } while(u > base_unsigned(y0 - 1)); 166 S = (S << w0) + (u & y0_mask); 167 } 168 for(std::size_t k = 0; k < (n - n0); ++k) { 169 base_unsigned u; 170 do { 171 u = detail::subtract<base_result>()(_base(), (_base.min)()); 172 } while(u > base_unsigned(y1 - 1)); 173 S = (S << (w0 + 1)) + (u & y1_mask); 174 } 175 return S; 176 } 177 178 /** Fills a range with random values */ 179 template<class Iter> generate(Iter first,Iter last)180 void generate(Iter first, Iter last) 181 { detail::generate_from_int(*this, first, last); } 182 183 /** Advances the state of the generator by @c z. */ discard(boost::uintmax_t z)184 void discard(boost::uintmax_t z) 185 { 186 for(boost::uintmax_t i = 0; i < z; ++i) { 187 (*this)(); 188 } 189 } 190 base() const191 const base_type& base() const { return _base; } 192 193 /** 194 * Writes the textual representation if the generator to a @c std::ostream. 195 * The textual representation of the engine is the textual representation 196 * of the base engine. 197 */ BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os,independent_bits_engine,r)198 BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, independent_bits_engine, r) 199 { 200 os << r._base; 201 return os; 202 } 203 204 /** 205 * Reads the state of an @c independent_bits_engine from a 206 * @c std::istream. 207 */ BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is,independent_bits_engine,r)208 BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, independent_bits_engine, r) 209 { 210 is >> r._base; 211 return is; 212 } 213 214 /** 215 * Returns: true iff the two @c independent_bits_engines will 216 * produce the same sequence of values. 217 */ BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(independent_bits_engine,x,y)218 BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(independent_bits_engine, x, y) 219 { return x._base == y._base; } 220 /** 221 * Returns: true iff the two @c independent_bits_engines will 222 * produce different sequences of values. 223 */ 224 BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(independent_bits_engine) 225 226 private: 227 228 /// \cond show_private 229 typedef typename base_type::result_type base_result; 230 typedef typename make_unsigned<base_result>::type base_unsigned; 231 calc_params(std::size_t n,base_unsigned range,std::size_t & w0,std::size_t & n0,base_unsigned & y0,base_unsigned & y1,base_unsigned & y0_mask,base_unsigned & y1_mask)232 void calc_params( 233 std::size_t n, base_unsigned range, 234 std::size_t& w0, std::size_t& n0, 235 base_unsigned& y0, base_unsigned& y1, 236 base_unsigned& y0_mask, base_unsigned& y1_mask) 237 { 238 BOOST_ASSERT(w >= n); 239 w0 = w/n; 240 n0 = n - w % n; 241 y0_mask = (base_unsigned(2) << (w0 - 1)) - 1; 242 y1_mask = (y0_mask << 1) | 1; 243 y0 = (range + 1) & ~y0_mask; 244 y1 = (range + 1) & ~y1_mask; 245 BOOST_ASSERT(y0 != 0 || base_unsigned(range + 1) == 0); 246 } 247 /// \endcond 248 249 Engine _base; 250 }; 251 252 #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION 253 template<class Engine, std::size_t w, class UIntType> 254 const bool independent_bits_engine<Engine, w, UIntType>::has_fixed_range; 255 #endif 256 257 } // namespace random 258 } // namespace boost 259 260 #endif // BOOST_RANDOM_INDEPENDENT_BITS_HPP 261