File indexing completed on 2025-01-18 09:51:12
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #ifndef BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP
0017 #define BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP
0018
0019 #include <boost/config/no_tr1/cmath.hpp> // std::pow
0020 #include <iostream>
0021 #include <algorithm> // std::equal
0022 #include <stdexcept>
0023 #include <boost/config.hpp>
0024 #include <boost/limits.hpp>
0025 #include <boost/cstdint.hpp>
0026 #include <boost/static_assert.hpp>
0027 #include <boost/integer/static_log2.hpp>
0028 #include <boost/integer/integer_mask.hpp>
0029 #include <boost/detail/workaround.hpp>
0030 #include <boost/random/detail/config.hpp>
0031 #include <boost/random/detail/seed.hpp>
0032 #include <boost/random/detail/operators.hpp>
0033 #include <boost/random/detail/seed_impl.hpp>
0034 #include <boost/random/detail/generator_seed_seq.hpp>
0035 #include <boost/random/linear_congruential.hpp>
0036
0037
0038 namespace boost {
0039 namespace random {
0040
0041 namespace detail {
0042
0043 struct subtract_with_carry_discard
0044 {
0045 template<class Engine>
0046 static void apply(Engine& eng, boost::uintmax_t z)
0047 {
0048 typedef typename Engine::result_type IntType;
0049 const std::size_t short_lag = Engine::short_lag;
0050 const std::size_t long_lag = Engine::long_lag;
0051 std::size_t k = eng.k;
0052 IntType carry = eng.carry;
0053 if(k != 0) {
0054
0055 if(k < short_lag) {
0056 std::size_t limit = (short_lag - k) < z?
0057 short_lag : (k + static_cast<std::size_t>(z));
0058 for(std::size_t j = k; j < limit; ++j) {
0059 carry = eng.do_update(j, j + long_lag - short_lag, carry);
0060 }
0061 }
0062 std::size_t limit = (long_lag - k) < z?
0063 long_lag : (k + static_cast<std::size_t>(z));
0064 std::size_t start = (k < short_lag ? short_lag : k);
0065 for(std::size_t j = start; j < limit; ++j) {
0066 carry = eng.do_update(j, j - short_lag, carry);
0067 }
0068 }
0069
0070 k = ((z % long_lag) + k) % long_lag;
0071
0072 if(k < z) {
0073
0074 for(std::size_t i = 0; i < (z - k) / long_lag; ++i) {
0075 for(std::size_t j = 0; j < short_lag; ++j) {
0076 carry = eng.do_update(j, j + long_lag - short_lag, carry);
0077 }
0078 for(std::size_t j = short_lag; j < long_lag; ++j) {
0079 carry = eng.do_update(j, j - short_lag, carry);
0080 }
0081 }
0082
0083
0084 std::size_t limit = short_lag < k? short_lag : k;
0085 for(std::size_t j = 0; j < limit; ++j) {
0086 carry = eng.do_update(j, j + long_lag - short_lag, carry);
0087 }
0088 for(std::size_t j = short_lag; j < k; ++j) {
0089 carry = eng.do_update(j, j - short_lag, carry);
0090 }
0091 }
0092 eng.carry = carry;
0093 eng.k = k;
0094 }
0095 };
0096
0097 }
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110 template<class IntType, std::size_t w, std::size_t s, std::size_t r>
0111 class subtract_with_carry_engine
0112 {
0113 public:
0114 typedef IntType result_type;
0115 BOOST_STATIC_CONSTANT(std::size_t, word_size = w);
0116 BOOST_STATIC_CONSTANT(std::size_t, long_lag = r);
0117 BOOST_STATIC_CONSTANT(std::size_t, short_lag = s);
0118 BOOST_STATIC_CONSTANT(uint32_t, default_seed = 19780503u);
0119
0120
0121 BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
0122
0123 BOOST_STATIC_CONSTANT(result_type, modulus = (result_type(1) << w));
0124
0125 BOOST_STATIC_ASSERT(std::numeric_limits<result_type>::is_integer);
0126
0127
0128
0129
0130
0131 subtract_with_carry_engine() { seed(); }
0132
0133
0134
0135
0136 BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry_engine,
0137 IntType, value)
0138 { seed(value); }
0139
0140
0141
0142
0143 BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(subtract_with_carry_engine,
0144 SeedSeq, seq)
0145 { seed(seq); }
0146
0147
0148
0149
0150
0151
0152
0153 template<class It> subtract_with_carry_engine(It& first, It last)
0154 { seed(first,last); }
0155
0156
0157
0158
0159 void seed() { seed(default_seed); }
0160 BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry_engine,
0161 IntType, value)
0162 {
0163 typedef linear_congruential_engine<uint32_t,40014,0,2147483563> gen_t;
0164 gen_t intgen(static_cast<boost::uint32_t>(value == 0 ? default_seed : value));
0165 detail::generator_seed_seq<gen_t> gen(intgen);
0166 seed(gen);
0167 }
0168
0169
0170 BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(subtract_with_carry, SeedSeq, seq)
0171 {
0172 detail::seed_array_int<w>(seq, x);
0173 carry = (x[long_lag-1] == 0);
0174 k = 0;
0175 }
0176
0177
0178
0179
0180
0181
0182
0183 template<class It>
0184 void seed(It& first, It last)
0185 {
0186 detail::fill_array_int<w>(first, last, x);
0187 carry = (x[long_lag-1] == 0);
0188 k = 0;
0189 }
0190
0191
0192 static BOOST_CONSTEXPR result_type min BOOST_PREVENT_MACRO_SUBSTITUTION ()
0193 { return 0; }
0194
0195 static BOOST_CONSTEXPR result_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
0196 { return boost::low_bits_mask_t<w>::sig_bits; }
0197
0198
0199 result_type operator()()
0200 {
0201 std::size_t short_index =
0202 (k < short_lag)?
0203 (k + long_lag - short_lag) :
0204 (k - short_lag);
0205 carry = do_update(k, short_index, carry);
0206 IntType result = x[k];
0207 ++k;
0208 if(k >= long_lag)
0209 k = 0;
0210 return result;
0211 }
0212
0213
0214 void discard(boost::uintmax_t z)
0215 {
0216 detail::subtract_with_carry_discard::apply(*this, z);
0217 }
0218
0219
0220 template<class It>
0221 void generate(It first, It last)
0222 { detail::generate_from_int(*this, first, last); }
0223
0224
0225 BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, subtract_with_carry_engine, f)
0226 {
0227 for(unsigned int j = 0; j < f.long_lag; ++j)
0228 os << f.compute(j) << ' ';
0229 os << f.carry;
0230 return os;
0231 }
0232
0233
0234 BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, subtract_with_carry_engine, f)
0235 {
0236 for(unsigned int j = 0; j < f.long_lag; ++j)
0237 is >> f.x[j] >> std::ws;
0238 is >> f.carry;
0239 f.k = 0;
0240 return is;
0241 }
0242
0243
0244
0245
0246
0247 BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(subtract_with_carry_engine, x_, y)
0248 {
0249 for(unsigned int j = 0; j < r; ++j)
0250 if(x_.compute(j) != y.compute(j))
0251 return false;
0252 return true;
0253 }
0254
0255
0256
0257
0258
0259 BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(subtract_with_carry_engine)
0260
0261 private:
0262
0263
0264 IntType compute(unsigned int index) const
0265 {
0266 return x[(k+index) % long_lag];
0267 }
0268
0269 friend struct detail::subtract_with_carry_discard;
0270
0271 IntType do_update(std::size_t current, std::size_t short_index, IntType carry_)
0272 {
0273 IntType delta;
0274 IntType temp = x[current] + carry_;
0275 if (x[short_index] >= temp) {
0276
0277 delta = x[short_index] - temp;
0278 carry_ = 0;
0279 } else {
0280
0281 delta = modulus - temp + x[short_index];
0282 carry_ = 1;
0283 }
0284 x[current] = delta;
0285 return carry_;
0286 }
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303 IntType x[long_lag];
0304 std::size_t k;
0305 IntType carry;
0306 };
0307
0308 #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
0309
0310 template<class IntType, std::size_t w, std::size_t s, std::size_t r>
0311 const bool subtract_with_carry_engine<IntType, w, s, r>::has_fixed_range;
0312 template<class IntType, std::size_t w, std::size_t s, std::size_t r>
0313 const IntType subtract_with_carry_engine<IntType, w, s, r>::modulus;
0314 template<class IntType, std::size_t w, std::size_t s, std::size_t r>
0315 const std::size_t subtract_with_carry_engine<IntType, w, s, r>::word_size;
0316 template<class IntType, std::size_t w, std::size_t s, std::size_t r>
0317 const std::size_t subtract_with_carry_engine<IntType, w, s, r>::long_lag;
0318 template<class IntType, std::size_t w, std::size_t s, std::size_t r>
0319 const std::size_t subtract_with_carry_engine<IntType, w, s, r>::short_lag;
0320 template<class IntType, std::size_t w, std::size_t s, std::size_t r>
0321 const uint32_t subtract_with_carry_engine<IntType, w, s, r>::default_seed;
0322 #endif
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337 template<class RealType, std::size_t w, std::size_t s, std::size_t r>
0338 class subtract_with_carry_01_engine
0339 {
0340 public:
0341 typedef RealType result_type;
0342 BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
0343 BOOST_STATIC_CONSTANT(std::size_t, word_size = w);
0344 BOOST_STATIC_CONSTANT(std::size_t, long_lag = r);
0345 BOOST_STATIC_CONSTANT(std::size_t, short_lag = s);
0346 BOOST_STATIC_CONSTANT(boost::uint32_t, default_seed = 19780503u);
0347
0348 BOOST_STATIC_ASSERT(!std::numeric_limits<result_type>::is_integer);
0349
0350
0351 subtract_with_carry_01_engine() { init_modulus(); seed(); }
0352
0353 BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry_01_engine,
0354 boost::uint32_t, value)
0355 { init_modulus(); seed(value); }
0356
0357
0358
0359
0360 BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(subtract_with_carry_01_engine,
0361 SeedSeq, seq)
0362 { init_modulus(); seed(seq); }
0363
0364
0365
0366
0367
0368
0369 template<class It> subtract_with_carry_01_engine(It& first, It last)
0370 { init_modulus(); seed(first,last); }
0371
0372 private:
0373
0374 void init_modulus()
0375 {
0376 #ifndef BOOST_NO_STDC_NAMESPACE
0377
0378 using std::pow;
0379 #endif
0380 _modulus = pow(RealType(2), RealType(word_size));
0381 }
0382
0383
0384 public:
0385
0386
0387
0388 void seed() { seed(default_seed); }
0389
0390
0391 BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry_01_engine,
0392 boost::uint32_t, value)
0393 {
0394 typedef linear_congruential_engine<uint32_t, 40014, 0, 2147483563> gen_t;
0395 gen_t intgen(value == 0 ? default_seed : value);
0396 detail::generator_seed_seq<gen_t> gen(intgen);
0397 seed(gen);
0398 }
0399
0400
0401 BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(subtract_with_carry_01_engine,
0402 SeedSeq, seq)
0403 {
0404 detail::seed_array_real<w>(seq, x);
0405 carry = (x[long_lag-1] ? result_type(0) : result_type(1 / _modulus));
0406 k = 0;
0407 }
0408
0409
0410
0411
0412
0413
0414
0415 template<class It>
0416 void seed(It& first, It last)
0417 {
0418 detail::fill_array_real<w>(first, last, x);
0419 carry = (x[long_lag-1] ? result_type(0) : result_type(1 / _modulus));
0420 k = 0;
0421 }
0422
0423
0424 static BOOST_CONSTEXPR result_type min BOOST_PREVENT_MACRO_SUBSTITUTION ()
0425 { return result_type(0); }
0426
0427 static BOOST_CONSTEXPR result_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
0428 { return result_type(1); }
0429
0430
0431 result_type operator()()
0432 {
0433 std::size_t short_index =
0434 (k < short_lag) ?
0435 (k + long_lag - short_lag) :
0436 (k - short_lag);
0437 carry = do_update(k, short_index, carry);
0438 RealType result = x[k];
0439 ++k;
0440 if(k >= long_lag)
0441 k = 0;
0442 return result;
0443 }
0444
0445
0446 void discard(boost::uintmax_t z)
0447 { detail::subtract_with_carry_discard::apply(*this, z); }
0448
0449
0450 template<class Iter>
0451 void generate(Iter first, Iter last)
0452 { detail::generate_from_real(*this, first, last); }
0453
0454
0455 BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, subtract_with_carry_01_engine, f)
0456 {
0457 std::ios_base::fmtflags oldflags =
0458 os.flags(os.dec | os.fixed | os.left);
0459 for(unsigned int j = 0; j < f.long_lag; ++j)
0460 os << (f.compute(j) * f._modulus) << ' ';
0461 os << (f.carry * f._modulus);
0462 os.flags(oldflags);
0463 return os;
0464 }
0465
0466
0467 BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, subtract_with_carry_01_engine, f)
0468 {
0469 RealType value;
0470 for(unsigned int j = 0; j < long_lag; ++j) {
0471 is >> value >> std::ws;
0472 f.x[j] = value / f._modulus;
0473 }
0474 is >> value;
0475 f.carry = value / f._modulus;
0476 f.k = 0;
0477 return is;
0478 }
0479
0480
0481 BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(subtract_with_carry_01_engine, x_, y)
0482 {
0483 for(unsigned int j = 0; j < r; ++j)
0484 if(x_.compute(j) != y.compute(j))
0485 return false;
0486 return true;
0487 }
0488
0489
0490 BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(subtract_with_carry_01_engine)
0491
0492 private:
0493
0494 RealType compute(unsigned int index) const
0495 {
0496 return x[(k+index) % long_lag];
0497 }
0498
0499 friend struct detail::subtract_with_carry_discard;
0500
0501 RealType do_update(std::size_t current, std::size_t short_index, RealType carry_)
0502 {
0503 RealType delta = x[short_index] - x[current] - carry_;
0504 if(delta < 0) {
0505 delta += RealType(1);
0506 carry_ = RealType(1)/_modulus;
0507 } else {
0508 carry_ = 0;
0509 }
0510 x[current] = delta;
0511 return carry_;
0512 }
0513
0514 std::size_t k;
0515 RealType carry;
0516 RealType x[long_lag];
0517 RealType _modulus;
0518 };
0519
0520 #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
0521
0522 template<class RealType, std::size_t w, std::size_t s, std::size_t r>
0523 const bool subtract_with_carry_01_engine<RealType, w, s, r>::has_fixed_range;
0524 template<class RealType, std::size_t w, std::size_t s, std::size_t r>
0525 const std::size_t subtract_with_carry_01_engine<RealType, w, s, r>::word_size;
0526 template<class RealType, std::size_t w, std::size_t s, std::size_t r>
0527 const std::size_t subtract_with_carry_01_engine<RealType, w, s, r>::long_lag;
0528 template<class RealType, std::size_t w, std::size_t s, std::size_t r>
0529 const std::size_t subtract_with_carry_01_engine<RealType, w, s, r>::short_lag;
0530 template<class RealType, std::size_t w, std::size_t s, std::size_t r>
0531 const uint32_t subtract_with_carry_01_engine<RealType, w, s, r>::default_seed;
0532 #endif
0533
0534
0535
0536
0537 template<class IntType, IntType m, unsigned s, unsigned r, IntType v>
0538 class subtract_with_carry :
0539 public subtract_with_carry_engine<IntType,
0540 boost::static_log2<m>::value, s, r>
0541 {
0542 typedef subtract_with_carry_engine<IntType,
0543 boost::static_log2<m>::value, s, r> base_type;
0544 public:
0545 subtract_with_carry() {}
0546 BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(subtract_with_carry, Gen, gen)
0547 { seed(gen); }
0548 BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry,
0549 IntType, val)
0550 { seed(val); }
0551 template<class It>
0552 subtract_with_carry(It& first, It last) : base_type(first, last) {}
0553 void seed() { base_type::seed(); }
0554 BOOST_RANDOM_DETAIL_GENERATOR_SEED(subtract_with_carry, Gen, gen)
0555 {
0556 detail::generator_seed_seq<Gen> seq(gen);
0557 base_type::seed(seq);
0558 }
0559 BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry, IntType, val)
0560 { base_type::seed(val); }
0561 template<class It>
0562 void seed(It& first, It last) { base_type::seed(first, last); }
0563 };
0564
0565 template<class RealType, int w, unsigned s, unsigned r, int v = 0>
0566 class subtract_with_carry_01 :
0567 public subtract_with_carry_01_engine<RealType, w, s, r>
0568 {
0569 typedef subtract_with_carry_01_engine<RealType, w, s, r> base_type;
0570 public:
0571 subtract_with_carry_01() {}
0572 BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(subtract_with_carry_01, Gen, gen)
0573 { seed(gen); }
0574 BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry_01,
0575 uint32_t, val)
0576 { seed(val); }
0577 template<class It>
0578 subtract_with_carry_01(It& first, It last) : base_type(first, last) {}
0579 void seed() { base_type::seed(); }
0580 BOOST_RANDOM_DETAIL_GENERATOR_SEED(subtract_with_carry_01, Gen, gen)
0581 {
0582 detail::generator_seed_seq<Gen> seq(gen);
0583 base_type::seed(seq);
0584 }
0585 BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry_01, uint32_t, val)
0586 { base_type::seed(val); }
0587 template<class It>
0588 void seed(It& first, It last) { base_type::seed(first, last); }
0589 };
0590
0591
0592
0593 namespace detail {
0594
0595 template<class Engine>
0596 struct generator_bits;
0597
0598 template<class RealType, std::size_t w, std::size_t s, std::size_t r>
0599 struct generator_bits<subtract_with_carry_01_engine<RealType, w, s, r> > {
0600 static std::size_t value() { return w; }
0601 };
0602
0603 template<class RealType, int w, unsigned s, unsigned r, int v>
0604 struct generator_bits<subtract_with_carry_01<RealType, w, s, r, v> > {
0605 static std::size_t value() { return w; }
0606 };
0607
0608 }
0609
0610 }
0611 }
0612
0613 #endif