From 6ce516d9edd2ca622deb9574451b496eaffbcb81 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Sat, 13 Jun 2009 17:54:06 +0000 Subject: [PATCH] Merge [53462], [53699], and [53800] from the trunk. [SVN r53871] --- include/boost/random/additive_combine.hpp | 8 ++ include/boost/random/detail/seed.hpp | 88 ++++++++++++ include/boost/random/discard_block.hpp | 1 + include/boost/random/lagged_fibonacci.hpp | 14 +- include/boost/random/linear_congruential.hpp | 22 ++- include/boost/random/mersenne_twister.hpp | 22 +-- include/boost/random/subtract_with_carry.hpp | 14 +- include/boost/random/uniform_int.hpp | 134 +++++++++++++++---- include/boost/random/xor_combine.hpp | 3 + instantiate.cpp | 55 +++++++- random-generators.html | 109 +++++++-------- random_test.cpp | 34 ++++- 12 files changed, 383 insertions(+), 121 deletions(-) create mode 100644 include/boost/random/detail/seed.hpp diff --git a/include/boost/random/additive_combine.hpp b/include/boost/random/additive_combine.hpp index 52aeb5d..8e9ab31 100644 --- a/include/boost/random/additive_combine.hpp +++ b/include/boost/random/additive_combine.hpp @@ -54,6 +54,8 @@ public: additive_combine(typename MLCG1::result_type seed1, typename MLCG2::result_type seed2) : _mlcg1(seed1), _mlcg2(seed2) { } + additive_combine(result_type seed) + : _mlcg1(seed), _mlcg2(seed) { } template additive_combine(It& first, It last) : _mlcg1(first, last), _mlcg2(first, last) { } @@ -63,6 +65,12 @@ public: _mlcg2.seed(); } + void seed(result_type seed) + { + _mlcg1.seed(seed); + _mlcg2.seed(seed); + } + void seed(typename MLCG1::result_type seed1, typename MLCG2::result_type seed2) { diff --git a/include/boost/random/detail/seed.hpp b/include/boost/random/detail/seed.hpp new file mode 100644 index 0000000..e6fc8b8 --- /dev/null +++ b/include/boost/random/detail/seed.hpp @@ -0,0 +1,88 @@ +/* boost random/detail/seed.hpp header file + * + * Copyright Steven Watanabe 2009 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + */ + +#ifndef BOOST_RANDOM_DETAIL_SEED_HPP +#define BOOST_RANDOM_DETAIL_SEED_HPP + +#include + +#if !defined(BOOST_NO_SFINAE) + +#include +#include + +namespace boost { +namespace random { +namespace detail { + +template +struct disable_seed : boost::disable_if > {}; + +template +struct disable_constructor : disable_seed {}; + +template +struct disable_constructor { +}; + +#define BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(Self, Generator, gen) \ + template \ + explicit Self(Generator& gen, typename ::boost::random::detail::disable_constructor::type* = 0) + +#define BOOST_RANDOM_DETAIL_GENERATOR_SEED(Self, Generator, gen) \ + template \ + void seed(Generator& gen, typename ::boost::random::detail::disable_seed::type* = 0) + +#define BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(Self, T, x) \ + explicit Self(const T& x) + +#define BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(Self, T, x) \ + void seed(const T& x) + +} +} +} + +#else + +#include +#include + +#define BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(Self, Generator, gen) \ + Self(Self& other) { *this = other; } \ + Self(const Self& other) { *this = other; } \ + template \ + explicit Self(Generator& gen) { \ + boost_random_constructor_impl(gen, ::boost::is_arithmetic());\ + } \ + template \ + void boost_random_constructor_impl(Generator& gen, ::boost::mpl::false_) + +#define BOOST_RANDOM_DETAIL_GENERATOR_SEED(Self, Generator, gen) \ + template \ + void seed(Generator& gen) { \ + boost_random_seed_impl(gen, ::boost::is_arithmetic());\ + }\ + template\ + void boost_random_seed_impl(Generator& gen, ::boost::mpl::false_) + +#define BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(Self, T, x) \ + explicit Self(const T& x) { boost_random_constructor_impl(x, ::boost::mpl::true_()); }\ + void boost_random_constructor_impl(const T& x, ::boost::mpl::true_) + +#define BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(Self, T, x) \ + void seed(const T& x) { boost_random_seed_impl(x, ::boost::mpl::true_()); }\ + void boost_random_seed_impl(const T& x, ::boost::mpl::true_) + +#endif + +#endif diff --git a/include/boost/random/discard_block.hpp b/include/boost/random/discard_block.hpp index da3f9b1..5c724fa 100644 --- a/include/boost/random/discard_block.hpp +++ b/include/boost/random/discard_block.hpp @@ -43,6 +43,7 @@ public: discard_block() : _rng(), _n(0) { } explicit discard_block(const base_type & rng) : _rng(rng), _n(0) { } + template explicit discard_block(T s) : _rng(s), _n(0) {} template discard_block(It& first, It last) : _rng(first, last), _n(0) { } void seed() { _rng.seed(); _n = 0; } diff --git a/include/boost/random/lagged_fibonacci.hpp b/include/boost/random/lagged_fibonacci.hpp index 25f9176..fa5069d 100644 --- a/include/boost/random/lagged_fibonacci.hpp +++ b/include/boost/random/lagged_fibonacci.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include namespace boost { @@ -267,9 +268,10 @@ public: BOOST_STATIC_CONSTANT(unsigned int, short_lag = q); lagged_fibonacci_01() { init_modulus(); seed(); } - explicit lagged_fibonacci_01(uint32_t value) { init_modulus(); seed(value); } - template - explicit lagged_fibonacci_01(Generator & gen) { init_modulus(); seed(gen); } + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(lagged_fibonacci_01, uint32_t, value) + { init_modulus(); seed(value); } + BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(lagged_fibonacci_01, Generator, gen) + { init_modulus(); seed(gen); } template lagged_fibonacci_01(It& first, It last) { init_modulus(); seed(first, last); } // compiler-generated copy ctor and assignment operator are fine @@ -285,7 +287,8 @@ private: } public: - void seed(uint32_t value = 331u) + void seed() { seed(331u); } + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(lagged_fibonacci_01, uint32_t, value) { minstd_rand0 intgen(value); seed(intgen); @@ -294,8 +297,7 @@ public: // For GCC, moving this function out-of-line prevents inlining, which may // reduce overall object code size. However, MSVC does not grok // out-of-line template member functions. - template - void seed(Generator & gen) + BOOST_RANDOM_DETAIL_GENERATOR_SEED(lagged_fibonacci, Generator, gen) { // use pass-by-reference, but wrap argument in pass_through_engine typedef detail::pass_through_engine ref_gen; diff --git a/include/boost/random/linear_congruential.hpp b/include/boost/random/linear_congruential.hpp index 7ea1cd2..f95387d 100644 --- a/include/boost/random/linear_congruential.hpp +++ b/include/boost/random/linear_congruential.hpp @@ -212,12 +212,12 @@ public: int32_t min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 0; } int32_t max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return std::numeric_limits::max BOOST_PREVENT_MACRO_SUBSTITUTION (); } - explicit rand48(int32_t x0 = 1) : lcf(cnv(x0)) { } - explicit rand48(uint64_t x0) : lcf(x0) { } + rand48() : lcf(cnv(static_cast(1))) {} + template explicit rand48(T x0) : lcf(cnv(x0)) { } template rand48(It& first, It last) : lcf(first, last) { } // compiler-generated copy ctor and assignment operator are fine - void seed(int32_t x0 = 1) { lcf.seed(cnv(x0)); } - void seed(uint64_t x0) { lcf.seed(x0); } + void seed() { seed(static_cast(1)); } + template void seed(T x0) { lcf.seed(cnv(x0)); } template void seed(It& first, It last) { lcf.seed(first,last); } int32_t operator()() { return static_cast(lcf() >> 17); } @@ -253,8 +253,18 @@ private: random::linear_congruential lcf; - static uint64_t cnv(int32_t x) - { return (static_cast(x) << 16) | 0x330e; } + template + static uint64_t cnv(T x) + { + if(sizeof(T) < sizeof(uint64_t)) { + return (static_cast(x) << 16) | 0x330e; + } else { + return(static_cast(x)); + } + } + static uint64_t cnv(float x) { return(static_cast(x)); } + static uint64_t cnv(double x) { return(static_cast(x)); } + static uint64_t cnv(long double x) { return(static_cast(x)); } }; #endif /* !BOOST_NO_INT64_T && !BOOST_NO_INTEGRAL_INT64_T */ diff --git a/include/boost/random/mersenne_twister.hpp b/include/boost/random/mersenne_twister.hpp index 21080fd..f0058fa 100644 --- a/include/boost/random/mersenne_twister.hpp +++ b/include/boost/random/mersenne_twister.hpp @@ -28,6 +28,7 @@ #include #include #include +#include namespace boost { namespace random { @@ -55,28 +56,18 @@ public: mersenne_twister() { seed(); } -#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x520) - // Work around overload resolution problem (Gennadiy E. Rozental) - explicit mersenne_twister(const UIntType& value) -#else - explicit mersenne_twister(UIntType value) -#endif + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(mersenne_twister, UIntType, value) { seed(value); } template mersenne_twister(It& first, It last) { seed(first,last); } - template - explicit mersenne_twister(Generator & gen) { seed(gen); } + BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(mersenne_twister, Generator, gen) + { seed(gen); } // compiler-generated copy ctor and assignment operator are fine void seed() { seed(UIntType(5489)); } -#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x520) - // Work around overload resolution problem (Gennadiy E. Rozental) - void seed(const UIntType& value) -#else - void seed(UIntType value) -#endif + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(mersenne_twister, UIntType, value) { // New seeding algorithm from // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html @@ -93,8 +84,7 @@ public: // For GCC, moving this function out-of-line prevents inlining, which may // reduce overall object code size. However, MSVC does not grok // out-of-line definitions of member function templates. - template - void seed(Generator & gen) + BOOST_RANDOM_DETAIL_GENERATOR_SEED(mersenne_twister, Generator, gen) { #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS BOOST_STATIC_ASSERT(!std::numeric_limits::is_signed); diff --git a/include/boost/random/subtract_with_carry.hpp b/include/boost/random/subtract_with_carry.hpp index c30baa6..a6665c6 100644 --- a/include/boost/random/subtract_with_carry.hpp +++ b/include/boost/random/subtract_with_carry.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -86,14 +87,16 @@ public: #endif seed(); } - explicit subtract_with_carry(uint32_t value) { seed(value); } - template - explicit subtract_with_carry(Generator & gen) { seed(gen); } + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry, uint32_t, value) + { seed(value); } + BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(subtract_with_carry, Generator, gen) + { seed(gen); } template subtract_with_carry(It& first, It last) { seed(first,last); } // compiler-generated copy ctor and assignment operator are fine - void seed(uint32_t value = 19780503u) + void seed() { seed(19780503u); } + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry, uint32_t, value) { random::linear_congruential intgen(value); seed(intgen); @@ -102,8 +105,7 @@ public: // For GCC, moving this function out-of-line prevents inlining, which may // reduce overall object code size. However, MSVC does not grok // out-of-line template member functions. - template - void seed(Generator & gen) + BOOST_RANDOM_DETAIL_GENERATOR_SEED(subtract_with_carry, Generator, gen) { // I could have used std::generate_n, but it takes "gen" by value for(unsigned int j = 0; j < long_lag; ++j) diff --git a/include/boost/random/uniform_int.hpp b/include/boost/random/uniform_int.hpp index 8d7f4a0..38823a8 100644 --- a/include/boost/random/uniform_int.hpp +++ b/include/boost/random/uniform_int.hpp @@ -23,13 +23,9 @@ #include #include #include -#include #include #include #include -#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS -#include -#endif namespace boost { @@ -119,45 +115,135 @@ private: for(;;) { // concatenate several invocations of the base RNG // take extra care to avoid overflows + + // limit == floor((range+1)/(brange+1)) + // Therefore limit*(brange+1) <= range+1 range_type limit; if(range == (std::numeric_limits::max)()) { limit = range/(range_type(brange)+1); - if(range % range_type(brange)+1 == range_type(brange)) + if(range % (range_type(brange)+1) == range_type(brange)) ++limit; } else { limit = (range+1)/(range_type(brange)+1); } + // We consider "result" as expressed to base (brange+1): // For every power of (brange+1), we determine a random factor range_type result = range_type(0); range_type mult = range_type(1); + + // loop invariants: + // result < mult + // mult <= range while(mult <= limit) { + // Postcondition: result <= range, thus no overflow + // + // limit*(brange+1)<=range+1 def. of limit (1) + // eng()-bmin<=brange eng() post. (2) + // and mult<=limit. loop condition (3) + // Therefore mult*(eng()-bmin+1)<=range+1 by (1),(2),(3) (4) + // Therefore mult*(eng()-bmin)+mult<=range+1 rearranging (4) (5) + // result()(eng(), bmin) * mult; + + // equivalent to (mult * (brange+1)) == range+1, but avoids overflow. + if(mult * range_type(brange) == range - mult + 1) { + // The destination range is an integer power of + // the generator's range. + return(result); + } + + // Postcondition: mult <= range + // + // limit*(brange+1)<=range+1 def. of limit (1) + // mult<=limit loop condition (2) + // Therefore mult*(brange+1)<=range+1 by (1), (2) (3) + // mult*(brange+1)!=range+1 preceding if (4) + // Therefore mult*(brange+1) limit loop condition (1) + // Suppose range/mult >= brange+1 Assumption (2) + // range >= mult*(brange+1) by (2) (3) + // range+1 > mult*(brange+1) by (3) (4) + // range+1 > (limit+1)*(brange+1) by (1), (4) (5) + // (range+1)/(brange+1) > limit+1 by (5) (6) + // limit < floor((range+1)/(brange+1)) by (6) (7) + // limit==floor((range+1)/(brange+1)) def. of limit (8) + // not (2) reductio (9) + // + // loop postcondition: (range/mult)*mult+(mult-1) >= range + // + // (range/mult)*mult + range%mult == range identity (1) + // range%mult < mult def. of % (2) + // (range/mult)*mult+mult > range by (1), (2) (3) + // (range/mult)*mult+(mult-1) >= range by (3) (4) + // + // Note that the maximum value of result at this point is (mult-1), + // so after this final step, we generate numbers that can be + // at least as large as range. We have to really careful to avoid + // overflow in this final addition and in the rejection. Anything + // that overflows is larger than range and can thus be rejected. + // range/mult < brange+1 -> no endless loop - result += uniform_int(0, range/mult)(eng) * mult; - if(result <= range) - return random::detail::add()(result, min_value); + range_type result_increment = uniform_int(0, range/mult)(eng); + if((std::numeric_limits::max)() / mult < result_increment) { + // The multiplcation would overflow. Reject immediately. + continue; + } + result_increment *= mult; + // unsigned integers are guaranteed to wrap on overflow. + result += result_increment; + if(result < result_increment) { + // The addition overflowed. Reject. + continue; + } + if(result > range) { + // Too big. Reject. + continue; + } + return random::detail::add()(result, min_value); } } else { // brange > range - if(brange / range > 4 /* quantization_cutoff */ ) { - // the new range is vastly smaller than the source range, - // so quantization effects are not relevant - return boost::uniform_smallint(min_value, max_value)(eng); - } else { - // use rejection method to handle cases like 0..5 -> 0..4 - for(;;) { - base_unsigned result = - random::detail::subtract()(eng(), bmin); - // result and range are non-negative, and result is possibly larger - // than range, so the cast is safe - if(result <= static_cast(range)) - return random::detail::add()(result, min_value); + base_unsigned bucket_size; + // it's safe to add 1 to range, as long as we cast it first, + // because we know that it is less than brange. However, + // we do need to be careful not to cause overflow by adding 1 + // to brange. + if(brange == (std::numeric_limits::max)()) { + bucket_size = brange / (static_cast(range)+1); + if(brange % (static_cast(range)+1) == static_cast(range)) { + ++bucket_size; } + } else { + bucket_size = (brange+1) / (static_cast(range)+1); + } + for(;;) { + base_unsigned result = + random::detail::subtract()(eng(), bmin); + result /= bucket_size; + // result and range are non-negative, and result is possibly larger + // than range, so the cast is safe + if(result <= static_cast(range)) + return random::detail::add()(result, min_value); } } } diff --git a/include/boost/random/xor_combine.hpp b/include/boost/random/xor_combine.hpp index e424275..ad94fd1 100644 --- a/include/boost/random/xor_combine.hpp +++ b/include/boost/random/xor_combine.hpp @@ -49,9 +49,12 @@ public: { } xor_combine(const base1_type & rng1, const base2_type & rng2) : _rng1(rng1), _rng2(rng2) { } + xor_combine(const result_type & v) + : _rng1(v), _rng2(v) { } template xor_combine(It& first, It last) : _rng1(first, last), _rng2( /* advanced by other call */ first, last) { } void seed() { _rng1.seed(); _rng2.seed(); } + void seed(const result_type & v) { _rng1.seed(v); _rng2.seed(v); } template void seed(It& first, It last) { _rng1.seed(first, last); diff --git a/instantiate.cpp b/instantiate.cpp index 15bfa7b..b95e446 100644 --- a/instantiate.cpp +++ b/instantiate.cpp @@ -129,12 +129,61 @@ void instantiate_real_dist(URNG& urng, RealType /* ignored */) boost::gamma_distribution(1)); } +template +void test_seed(URNG & urng, const T & t) { + URNG urng2(t); + BOOST_CHECK(urng == urng2); + urng2.seed(t); + BOOST_CHECK(urng == urng2); +} + +// rand48 uses non-standard seeding +template +void test_seed(boost::rand48 & urng, const T & t) { + boost::rand48 urng2(t); + urng2.seed(t); +} + template -void instantiate_urng(const std::string & s, const URNG &, const ResultType &) +void instantiate_seed(const URNG &, const ResultType &) { + { + URNG urng; + URNG urng2; + urng2.seed(); + BOOST_CHECK(urng == urng2); + } + { + int value = 127; + URNG urng(value); + + // integral types + test_seed(urng, static_cast(value)); + test_seed(urng, static_cast(value)); + test_seed(urng, static_cast(value)); + test_seed(urng, static_cast(value)); + test_seed(urng, static_cast(value)); + test_seed(urng, static_cast(value)); + test_seed(urng, static_cast(value)); + test_seed(urng, static_cast(value)); + test_seed(urng, static_cast(value)); +#if !defined(BOOST_NO_INT64_T) + test_seed(urng, static_cast(value)); + test_seed(urng, static_cast(value)); +#endif + + // floating point types + test_seed(urng, static_cast(value)); + test_seed(urng, static_cast(value)); + test_seed(urng, static_cast(value)); + } +} + +template +void instantiate_urng(const std::string & s, const URNG & u, const ResultType & r) { std::cout << "Basic tests for " << s; URNG urng; - urng.seed(); // seed() member function + instantiate_seed(u, r); // seed() member function int a[URNG::has_fixed_range ? 5 : 10]; // compile-time constant (void) a; // avoid "unused" warning typename URNG::result_type x1 = urng(); @@ -148,6 +197,8 @@ void instantiate_urng(const std::string & s, const URNG &, const ResultType &) urng(); urng2 = urng; // copy assignment BOOST_CHECK(urng == urng2); + urng2 = URNG(urng2); // copy constructor, not templated constructor + BOOST_CHECK(urng == urng2); #endif // BOOST_MSVC const std::vector v(9999u, 0x41); diff --git a/random-generators.html b/random-generators.html index de0c965..d01f2b1 100644 --- a/random-generators.html +++ b/random-generators.html @@ -35,8 +35,8 @@
  • Class template random::mersenne_twister
  • -
  • Class template - random::lagged_fibonacci
  • +
  • Class template + random::lagged_fibonacci_01
  • Performance
  • @@ -351,18 +351,18 @@ namespace boost { typedef random::mersenne_twister< /* ... */ > mt19937; namespace random { - template<class FloatType, unsigned int p, unsigned int q> - class lagged_fibonacci; + template<class FloatType, int w, unsigned int p, unsigned int q> + class lagged_fibonacci_01; } - typedef random::lagged_fibonacci< /* ... */ > lagged_fibonacci607; - typedef random::lagged_fibonacci< /* ... */ > lagged_fibonacci1279; - typedef random::lagged_fibonacci< /* ... */ > lagged_fibonacci2281; - typedef random::lagged_fibonacci< /* ... */ > lagged_fibonacci3217; - typedef random::lagged_fibonacci< /* ... */ > lagged_fibonacci4423; - typedef random::lagged_fibonacci< /* ... */ > lagged_fibonacci9689; - typedef random::lagged_fibonacci< /* ... */ > lagged_fibonacci19937; - typedef random::lagged_fibonacci< /* ... */ > lagged_fibonacci23209; - typedef random::lagged_fibonacci< /* ... */ > lagged_fibonacci44497; + typedef random::lagged_fibonacci_01< /* ... */ > lagged_fibonacci607; + typedef random::lagged_fibonacci_01< /* ... */ > lagged_fibonacci1279; + typedef random::lagged_fibonacci_01< /* ... */ > lagged_fibonacci2281; + typedef random::lagged_fibonacci_01< /* ... */ > lagged_fibonacci3217; + typedef random::lagged_fibonacci_01< /* ... */ > lagged_fibonacci4423; + typedef random::lagged_fibonacci_01< /* ... */ > lagged_fibonacci9689; + typedef random::lagged_fibonacci_01< /* ... */ > lagged_fibonacci19937; + typedef random::lagged_fibonacci_01< /* ... */ > lagged_fibonacci23209; + typedef random::lagged_fibonacci_01< /* ... */ > lagged_fibonacci44497; } // namespace boost @@ -773,7 +773,7 @@ template<class T> void seed(T s) #include <boost/random/inversive_congruential.hpp> -template<class IntType, IntType a, IntType b, IntType p> +template<class IntType, IntType a, IntType b, IntType p, IntType val> class random::inversive_congruential { public: @@ -789,7 +789,7 @@ public: IntType operator()(); }; -typedef random::inversive_congruential<int32_t, 9102, 2147483647-36884165, 2147483647> hellekalek1995; +typedef random::inversive_congruential<int32_t, 9102, 2147483647-36884165, 2147483647, 0> hellekalek1995;

    Description

    @@ -812,7 +812,8 @@ typedef random::inversive_congruential<int32_t, 9102, 2147483647-36884165, 21

    The template parameter IntType shall denote a signed integral type large enough to hold p; a, b, and p are the parameters of the - generators.

    + generators. The template parameter val is the validation value checked by + validation.

    Note: The implementation currently uses the Euclidian Algorithm to compute the multiplicative inverse. Therefore, the inversive generators @@ -849,21 +850,19 @@ void seed(IntType y0) #include <boost/random/mersenne_twister.hpp> -template<class DataType, int w, int n, int m, int r, DataType a, int u, -int s, DataType b, int t, DataType c, int l, IntType val> +template<class UIntType, int w, int n, int m, int r, UIntType a, int u, + int s, UIntType b, int t, UIntType c, int l, UIntType val> class random::mersenne_twister { public: - typedef DataType result_type; - static const bool has_fixed_range = true; - static const result_type min_value; - static const result_type max_value; + typedef UIntType result_type; + static const bool has_fixed_range = false; mersenne_twister(); - explicit mersenne_twister(DataType value); + explicit mersenne_twister(UIntType value); template<class Generator> explicit mersenne_twister(Generator & gen); // compiler-generated copy ctor and assignment operator are fine void seed(); - void seed(DataType value); + void seed(UIntType value); template<class Generator> void seed(Generator & gen); result_type operator()(); bool validation(result_type) const; @@ -918,13 +917,9 @@ template<class Generator> explicit mersenne_twister(Generator & gen)

    Effects: Constructs a mersenne_twister and calls seed(gen).

    -

    Note: When using direct-initialization syntax with an lvalue - (e.g. in the variable definition Gen gen2(gen);), this - templated constructor will be preferred over the compiler-generated copy - constructor. For variable definitions which should copy the state of - another mersenne_twister, use e.g. Gen gen2 = - gen;, which is copy-initialization syntax and guaranteed to invoke - the copy constructor.

    +

    Note: The copy constructor will always be preferred over the + templated constructor. mersenne_twister takes special steps to guarantee + this.

    Seeding

    @@ -953,39 +948,35 @@ template<class Generator> void seed(Generator & gen)
       

    Complexity: Exactly n invocations of gen.

    -

    Note: When invoking seed with an lvalue, overload - resolution chooses the function template unless the type of the argument - exactly matches result_type. For other integer types, you - should convert the argument to result_type explicitly.

    -

    Specializations

    The specializations mt11213b and mt19937 are from the paper cited above.

    -

    Class template - random::lagged_fibonacci

    +

    Class template + random::lagged_fibonacci_01

    Synopsis

     #include <boost/random/lagged_fibonacci.hpp>
     
    -template<class FloatType, unsigned int p, unsigned int q>
    -class lagged_fibonacci
    +template<class FloatType, int w, unsigned int p, unsigned int q>
    +class lagged_fibonacci_01
     {
     public:
       typedef FloatType result_type;
       static const bool has_fixed_range = false;
    +  static const int word_size = w;
       static const unsigned int long_lag = p;
       static const unsigned int short_lag = q;
       result_type min() const { return 0.0; }
       result_type max() const { return 1.0; }
    -  lagged_fibonacci();
    -  explicit lagged_fibonacci(uint32_t value);
    +  lagged_fibonacci_01();
    +  explicit lagged_fibonacci_01(uint32_t value);
       template<class Generator>
    -  explicit lagged_fibonacci(Generator & gen);
    +  explicit lagged_fibonacci_01(Generator & gen);
       // compiler-generated copy ctor and assignment operator are fine
       void seed(uint32_t value = 331u);
       template<class Generator> void seed(Generator & gen);
    @@ -993,15 +984,15 @@ public:
       bool validation(result_type x) const;
     };
     
    -typedef random::lagged_fibonacci<double, 607, 273> lagged_fibonacci607;
    -typedef random::lagged_fibonacci<double, 1279, 418> lagged_fibonacci1279;
    -typedef random::lagged_fibonacci<double, 2281, 1252> lagged_fibonacci2281;
    -typedef random::lagged_fibonacci<double, 3217, 576> lagged_fibonacci3217;
    -typedef random::lagged_fibonacci<double, 4423, 2098> lagged_fibonacci4423;
    -typedef random::lagged_fibonacci<double, 9689, 5502> lagged_fibonacci9689;
    -typedef random::lagged_fibonacci<double, 19937, 9842> lagged_fibonacci19937;
    -typedef random::lagged_fibonacci<double, 23209, 13470> lagged_fibonacci23209;
    -typedef random::lagged_fibonacci<double, 44497, 21034> lagged_fibonacci44497;
    +typedef random::lagged_fibonacci_01<double, 48, 607, 273> lagged_fibonacci607;
    +typedef random::lagged_fibonacci_01<double, 48, 1279, 418> lagged_fibonacci1279;
    +typedef random::lagged_fibonacci_01<double, 48, 2281, 1252> lagged_fibonacci2281;
    +typedef random::lagged_fibonacci_01<double, 48, 3217, 576> lagged_fibonacci3217;
    +typedef random::lagged_fibonacci_01<double, 48, 4423, 2098> lagged_fibonacci4423;
    +typedef random::lagged_fibonacci_01<double, 48, 9689, 5502> lagged_fibonacci9689;
    +typedef random::lagged_fibonacci_01<double, 48, 19937, 9842> lagged_fibonacci19937;
    +typedef random::lagged_fibonacci_01<double, 48, 23209, 13470> lagged_fibonacci23209;
    +typedef random::lagged_fibonacci_01<double, 48, 44497, 21034> lagged_fibonacci44497;
     

    Description

    @@ -1029,22 +1020,22 @@ typedef random::lagged_fibonacci<double, 44497, 21034> lagged_fibonacci444

    Constructors

    -lagged_fibonacci()
    +lagged_fibonacci_01()
     
    -

    Effects: Constructs a lagged_fibonacci +

    Effects: Constructs a lagged_fibonacci_01 generator and calls seed().

    -explicit lagged_fibonacci(uint32_t value)
    +explicit lagged_fibonacci_01(uint32_t value)
     
    -

    Effects: Constructs a lagged_fibonacci +

    Effects: Constructs a lagged_fibonacci_01 generator and calls seed(value).

    -template<class Generator> explicit lagged_fibonacci(Generator & gen)
    +template<class Generator> explicit lagged_fibonacci_01(Generator & gen)
     
    -

    Effects: Constructs a lagged_fibonacci +

    Effects: Constructs a lagged_fibonacci_01 generator and calls seed(gen).

    Seeding

    @@ -1065,7 +1056,7 @@ template<class Generator> void seed(Generator & gen)

    Effects: Sets the state of this - lagged_fibonacci to the values returned by p + lagged_fibonacci_01 to the values returned by p invocations of uniform_01<gen, FloatType>.
    Complexity: Exactly p invocations of gen.

    diff --git a/random_test.cpp b/random_test.cpp index a1280fd..6a7078e 100644 --- a/random_test.cpp +++ b/random_test.cpp @@ -64,7 +64,8 @@ void check_uniform_int(Generator & gen, int iter) for(int k = 0; k < range; k++) sum += bucket[k]; double avg = static_cast(sum)/range; - double threshold = 2*avg/std::sqrt(static_cast(iter)); + double p = 1 / static_cast(range); + double threshold = 2*std::sqrt(static_cast(iter)*p*(1-p)); for(int i = 0; i < range; i++) { if(std::fabs(bucket[i] - avg) > threshold) { // 95% confidence interval @@ -100,11 +101,37 @@ void test_uniform_int(Generator & gen) // small range => larger range level_two uint05(uint12, int_gen(-3, 2)); check_uniform_int(uint05, 100000); + + // small range => larger range + level_two uint099(uint12, int_gen(0, 99)); + check_uniform_int(uint099, 100000); // larger => small range, rejection case typedef boost::variate_generator level_three; level_three uint1_4(uint05, int_gen(1, 4)); check_uniform_int(uint1_4, 100000); + + typedef boost::uniform_int int8_gen; + typedef boost::variate_generator gen8_t; + + gen8_t gen8_03(gen, int8_gen(0, 3)); + + // use the full range of the type, where the destination + // range is a power of the source range + typedef boost::variate_generator uniform_uint8; + uniform_uint8 uint8_0255(gen8_03, int8_gen(0, 255)); + check_uniform_int(uint8_0255, 100000); + + // use the full range, but a generator whose range is not + // a root of the destination range. + gen8_t gen8_02(gen, int8_gen(0, 2)); + uniform_uint8 uint8_0255_2(gen8_02, int8_gen(0, 255)); + check_uniform_int(uint8_0255_2, 100000); + + // expand the range to a larger type. + typedef boost::variate_generator uniform_uint_from8; + uniform_uint_from8 uint0300(gen8_03, int_gen(0, 300)); + check_uniform_int(uint0300, 100000); } #if defined(BOOST_MSVC) && _MSC_VER < 1300 @@ -140,10 +167,13 @@ INSTANT(boost::mt11213b) class ruetti_gen { public: + ruetti_gen() : state((max)() - 1) {} typedef boost::uint64_t result_type; result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 0; } result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return std::numeric_limits::max BOOST_PREVENT_MACRO_SUBSTITUTION (); } - result_type operator()() { return (max)()-1; } + result_type operator()() { return state--; } +private: + result_type state; }; void test_overflow_range()