File indexing completed on 2025-01-18 09:51:11
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef BOOST_RANDOM_INDEPENDENT_BITS_HPP
0015 #define BOOST_RANDOM_INDEPENDENT_BITS_HPP
0016
0017 #include <istream>
0018 #include <iosfwd>
0019 #include <boost/assert.hpp>
0020 #include <boost/limits.hpp>
0021 #include <boost/config.hpp>
0022 #include <boost/cstdint.hpp>
0023 #include <boost/integer/integer_mask.hpp>
0024 #include <boost/random/traits.hpp>
0025 #include <boost/random/detail/config.hpp>
0026 #include <boost/random/detail/integer_log2.hpp>
0027 #include <boost/random/detail/operators.hpp>
0028 #include <boost/random/detail/seed.hpp>
0029 #include <boost/random/detail/seed_impl.hpp>
0030 #include <boost/random/detail/signed_unsigned_tools.hpp>
0031
0032 namespace boost {
0033 namespace random {
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043 template<class Engine, std::size_t w, class UIntType>
0044 class independent_bits_engine
0045 {
0046 public:
0047 typedef Engine base_type;
0048 typedef UIntType result_type;
0049 typedef typename Engine::result_type base_result_type;
0050
0051
0052 BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
0053
0054
0055 static BOOST_CONSTEXPR result_type min BOOST_PREVENT_MACRO_SUBSTITUTION ()
0056 { return 0; }
0057
0058 static BOOST_CONSTEXPR result_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
0059 { return max_imp(boost::is_integral<UIntType>()); }
0060
0061
0062
0063
0064
0065 independent_bits_engine() { }
0066
0067
0068
0069
0070
0071 BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(independent_bits_engine,
0072 base_result_type, seed_arg)
0073 {
0074 _base.seed(seed_arg);
0075 }
0076
0077
0078
0079
0080
0081 BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(independent_bits_engine,
0082 SeedSeq, seq)
0083 { _base.seed(seq); }
0084
0085
0086 independent_bits_engine(const base_type& base_arg) : _base(base_arg) {}
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098 template<class It>
0099 independent_bits_engine(It& first, It last) : _base(first, last) { }
0100
0101
0102
0103
0104
0105 void seed() { _base.seed(); }
0106
0107
0108
0109
0110
0111 BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(independent_bits_engine,
0112 base_result_type, seed_arg)
0113 { _base.seed(seed_arg); }
0114
0115
0116
0117
0118
0119 BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(independent_bits_engine,
0120 SeedSeq, seq)
0121 { _base.seed(seq); }
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133 template<class It> void seed(It& first, It last)
0134 { _base.seed(first, last); }
0135
0136
0137 result_type operator()()
0138 {
0139
0140
0141
0142 base_unsigned range =
0143 detail::subtract<base_result_type>()((_base.max)(), (_base.min)());
0144 std::size_t m =
0145 (range == (std::numeric_limits<base_unsigned>::max)()) ?
0146 std::numeric_limits<base_unsigned>::digits :
0147 detail::integer_log2(range + 1);
0148 std::size_t n = (w + m - 1) / m;
0149 std::size_t w0, n0;
0150 base_unsigned y0, y1;
0151 base_unsigned y0_mask, y1_mask;
0152 calc_params(n, range, w0, n0, y0, y1, y0_mask, y1_mask);
0153 if(base_unsigned(range - y0 + 1) > y0 / n) {
0154
0155 ++n;
0156 calc_params(n, range, w0, n0, y0, y1, y0_mask, y1_mask);
0157 }
0158
0159 BOOST_ASSERT(n0*w0 + (n - n0)*(w0 + 1) == w);
0160
0161 BOOST_ASSERT((n == 1) == (w0 == w));
0162
0163
0164 if(n == 1) {
0165 BOOST_ASSERT(n0 == 1);
0166 base_unsigned u;
0167 do {
0168 u = detail::subtract<base_result_type>()(_base(), (_base.min)());
0169 } while(u > base_unsigned(y0 - 1));
0170 return u & y0_mask;
0171 }
0172
0173 result_type S = 0;
0174 for(std::size_t k = 0; k < n0; ++k) {
0175 base_unsigned u;
0176 do {
0177 u = detail::subtract<base_result_type>()(_base(), (_base.min)());
0178 } while(u > base_unsigned(y0 - 1));
0179 S = (S << w0) + (u & y0_mask);
0180 }
0181 for(std::size_t k = 0; k < (n - n0); ++k) {
0182 base_unsigned u;
0183 do {
0184 u = detail::subtract<base_result_type>()(_base(), (_base.min)());
0185 } while(u > base_unsigned(y1 - 1));
0186 S = (S << (w0 + 1)) + (u & y1_mask);
0187 }
0188 return S;
0189 }
0190
0191
0192 template<class Iter>
0193 void generate(Iter first, Iter last)
0194 { detail::generate_from_int(*this, first, last); }
0195
0196
0197 void discard(boost::uintmax_t z)
0198 {
0199 for(boost::uintmax_t i = 0; i < z; ++i) {
0200 (*this)();
0201 }
0202 }
0203
0204 const base_type& base() const { return _base; }
0205
0206
0207
0208
0209
0210
0211 BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, independent_bits_engine, r)
0212 {
0213 os << r._base;
0214 return os;
0215 }
0216
0217
0218
0219
0220
0221 BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, independent_bits_engine, r)
0222 {
0223 is >> r._base;
0224 return is;
0225 }
0226
0227
0228
0229
0230
0231 BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(independent_bits_engine, x, y)
0232 { return x._base == y._base; }
0233
0234
0235
0236
0237 BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(independent_bits_engine)
0238
0239 private:
0240
0241
0242 typedef typename boost::random::traits::make_unsigned<base_result_type>::type base_unsigned;
0243
0244 static BOOST_CONSTEXPR UIntType max_imp(const boost::true_type&)
0245 {
0246 return boost::low_bits_mask_t<w>::sig_bits;
0247 }
0248 static UIntType max_imp(const boost::false_type&)
0249 {
0250
0251 BOOST_STATIC_ASSERT(std::numeric_limits<UIntType>::is_specialized);
0252 return w < std::numeric_limits<UIntType>::digits ? UIntType((UIntType(1) << w) - 1) : UIntType((((UIntType(1) << (w - 1)) - 1) << 1) | 1u);
0253 }
0254
0255 void calc_params(
0256 std::size_t n, base_unsigned range,
0257 std::size_t& w0, std::size_t& n0,
0258 base_unsigned& y0, base_unsigned& y1,
0259 base_unsigned& y0_mask, base_unsigned& y1_mask)
0260 {
0261 BOOST_ASSERT(w >= n);
0262 w0 = w/n;
0263 n0 = n - w % n;
0264 y0_mask = (base_unsigned(2) << (w0 - 1)) - 1;
0265 y1_mask = (y0_mask << 1) | 1;
0266 y0 = (range + 1) & ~y0_mask;
0267 y1 = (range + 1) & ~y1_mask;
0268 BOOST_ASSERT(y0 != 0 || base_unsigned(range + 1) == 0);
0269 }
0270
0271
0272 Engine _base;
0273 };
0274
0275 #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
0276 template<class Engine, std::size_t w, class UIntType>
0277 const bool independent_bits_engine<Engine, w, UIntType>::has_fixed_range;
0278 #endif
0279
0280 }
0281 }
0282
0283 #endif