mirror of
https://github.com/boostorg/random.git
synced 2026-01-23 17:52:18 +00:00
Merge [53462], [53699], and [53800] from the trunk.
[SVN r53871]
This commit is contained in:
@@ -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<class It> 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)
|
||||
{
|
||||
|
||||
88
include/boost/random/detail/seed.hpp
Normal file
88
include/boost/random/detail/seed.hpp
Normal file
@@ -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 <boost/config.hpp>
|
||||
|
||||
#if !defined(BOOST_NO_SFINAE)
|
||||
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/type_traits/is_arithmetic.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace random {
|
||||
namespace detail {
|
||||
|
||||
template<class T>
|
||||
struct disable_seed : boost::disable_if<boost::is_arithmetic<T> > {};
|
||||
|
||||
template<class Engine, class T>
|
||||
struct disable_constructor : disable_seed<T> {};
|
||||
|
||||
template<class Engine>
|
||||
struct disable_constructor<Engine, Engine> {
|
||||
};
|
||||
|
||||
#define BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(Self, Generator, gen) \
|
||||
template<class Generator> \
|
||||
explicit Self(Generator& gen, typename ::boost::random::detail::disable_constructor<Self, Generator>::type* = 0)
|
||||
|
||||
#define BOOST_RANDOM_DETAIL_GENERATOR_SEED(Self, Generator, gen) \
|
||||
template<class Generator> \
|
||||
void seed(Generator& gen, typename ::boost::random::detail::disable_seed<Generator>::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 <boost/type_traits/is_arithmetic.hpp>
|
||||
#include <boost/mpl/bool.hpp>
|
||||
|
||||
#define BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(Self, Generator, gen) \
|
||||
Self(Self& other) { *this = other; } \
|
||||
Self(const Self& other) { *this = other; } \
|
||||
template<class Generator> \
|
||||
explicit Self(Generator& gen) { \
|
||||
boost_random_constructor_impl(gen, ::boost::is_arithmetic<Generator>());\
|
||||
} \
|
||||
template<class Generator> \
|
||||
void boost_random_constructor_impl(Generator& gen, ::boost::mpl::false_)
|
||||
|
||||
#define BOOST_RANDOM_DETAIL_GENERATOR_SEED(Self, Generator, gen) \
|
||||
template<class Generator> \
|
||||
void seed(Generator& gen) { \
|
||||
boost_random_seed_impl(gen, ::boost::is_arithmetic<Generator>());\
|
||||
}\
|
||||
template<class Generator>\
|
||||
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
|
||||
@@ -43,6 +43,7 @@ public:
|
||||
|
||||
discard_block() : _rng(), _n(0) { }
|
||||
explicit discard_block(const base_type & rng) : _rng(rng), _n(0) { }
|
||||
template<class T> explicit discard_block(T s) : _rng(s), _n(0) {}
|
||||
template<class It> discard_block(It& first, It last)
|
||||
: _rng(first, last), _n(0) { }
|
||||
void seed() { _rng.seed(); _n = 0; }
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <boost/random/linear_congruential.hpp>
|
||||
#include <boost/random/uniform_01.hpp>
|
||||
#include <boost/random/detail/config.hpp>
|
||||
#include <boost/random/detail/seed.hpp>
|
||||
#include <boost/random/detail/pass_through_engine.hpp>
|
||||
|
||||
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<class Generator>
|
||||
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<class It> 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<class Generator>
|
||||
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<Generator&> ref_gen;
|
||||
|
||||
@@ -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<int32_t>::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<int32_t>(1))) {}
|
||||
template<class T> explicit rand48(T x0) : lcf(cnv(x0)) { }
|
||||
template<class It> 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<int32_t>(1)); }
|
||||
template<class T> void seed(T x0) { lcf.seed(cnv(x0)); }
|
||||
template<class It> void seed(It& first, It last) { lcf.seed(first,last); }
|
||||
|
||||
int32_t operator()() { return static_cast<int32_t>(lcf() >> 17); }
|
||||
@@ -253,8 +253,18 @@ private:
|
||||
random::linear_congruential<uint64_t,
|
||||
uint64_t(0xDEECE66DUL) | (uint64_t(0x5) << 32), // xxxxULL is not portable
|
||||
0xB, uint64_t(1)<<48, /* unknown */ 0> lcf;
|
||||
static uint64_t cnv(int32_t x)
|
||||
{ return (static_cast<uint64_t>(x) << 16) | 0x330e; }
|
||||
template<class T>
|
||||
static uint64_t cnv(T x)
|
||||
{
|
||||
if(sizeof(T) < sizeof(uint64_t)) {
|
||||
return (static_cast<uint64_t>(x) << 16) | 0x330e;
|
||||
} else {
|
||||
return(static_cast<uint64_t>(x));
|
||||
}
|
||||
}
|
||||
static uint64_t cnv(float x) { return(static_cast<uint64_t>(x)); }
|
||||
static uint64_t cnv(double x) { return(static_cast<uint64_t>(x)); }
|
||||
static uint64_t cnv(long double x) { return(static_cast<uint64_t>(x)); }
|
||||
};
|
||||
#endif /* !BOOST_NO_INT64_T && !BOOST_NO_INTEGRAL_INT64_T */
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/random/detail/config.hpp>
|
||||
#include <boost/random/detail/ptr_helper.hpp>
|
||||
#include <boost/random/detail/seed.hpp>
|
||||
|
||||
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<class It> mersenne_twister(It& first, It last) { seed(first,last); }
|
||||
|
||||
template<class Generator>
|
||||
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<class Generator>
|
||||
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<result_type>::is_signed);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/random/detail/config.hpp>
|
||||
#include <boost/random/detail/seed.hpp>
|
||||
#include <boost/random/linear_congruential.hpp>
|
||||
|
||||
|
||||
@@ -86,14 +87,16 @@ public:
|
||||
#endif
|
||||
seed();
|
||||
}
|
||||
explicit subtract_with_carry(uint32_t value) { seed(value); }
|
||||
template<class Generator>
|
||||
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<class It> 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<int32_t, 40014, 0, 2147483563, 0> 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<class Generator>
|
||||
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)
|
||||
|
||||
@@ -23,13 +23,9 @@
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/random/uniform_smallint.hpp>
|
||||
#include <boost/random/detail/config.hpp>
|
||||
#include <boost/random/detail/signed_unsigned_tools.hpp>
|
||||
#include <boost/type_traits/make_unsigned.hpp>
|
||||
#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
||||
#include <boost/type_traits/is_float.hpp>
|
||||
#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<range_type>::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<mult loop invariant (6)
|
||||
// Therefore result+mult*(eng()-bmin)<range+1 by (5), (6) (7)
|
||||
//
|
||||
// Postcondition: result < mult*(brange+1)
|
||||
//
|
||||
// result<mult loop invariant (1)
|
||||
// eng()-bmin<=brange eng() post. (2)
|
||||
// Therefore result+mult*(eng()-bmin) <
|
||||
// mult+mult*(eng()-bmin) by (1) (3)
|
||||
// Therefore result+(eng()-bmin)*mult <
|
||||
// mult+mult*brange by (2), (3) (4)
|
||||
// Therefore result+(eng()-bmin)*mult <
|
||||
// mult*(brange+1) by (4)
|
||||
result += random::detail::subtract<base_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)<range+1 by (3), (4) (5)
|
||||
//
|
||||
// Postcondition: result < mult
|
||||
//
|
||||
// See the second postcondition on the change to result.
|
||||
mult *= range_type(brange)+range_type(1);
|
||||
}
|
||||
if(mult == limit)
|
||||
// range+1 is an integer power of brange+1: no rejections required
|
||||
return result;
|
||||
// loop postcondition: range/mult < brange+1
|
||||
//
|
||||
// mult > 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<range_type>(0, range/mult)(eng) * mult;
|
||||
if(result <= range)
|
||||
return random::detail::add<range_type, result_type>()(result, min_value);
|
||||
range_type result_increment = uniform_int<range_type>(0, range/mult)(eng);
|
||||
if((std::numeric_limits<range_type>::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<range_type, result_type>()(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<result_type>(min_value, max_value)(eng);
|
||||
} else {
|
||||
// use rejection method to handle cases like 0..5 -> 0..4
|
||||
for(;;) {
|
||||
base_unsigned result =
|
||||
random::detail::subtract<base_result>()(eng(), bmin);
|
||||
// result and range are non-negative, and result is possibly larger
|
||||
// than range, so the cast is safe
|
||||
if(result <= static_cast<base_unsigned>(range))
|
||||
return random::detail::add<base_unsigned, result_type>()(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<base_unsigned>::max)()) {
|
||||
bucket_size = brange / (static_cast<base_unsigned>(range)+1);
|
||||
if(brange % (static_cast<base_unsigned>(range)+1) == static_cast<base_unsigned>(range)) {
|
||||
++bucket_size;
|
||||
}
|
||||
} else {
|
||||
bucket_size = (brange+1) / (static_cast<base_unsigned>(range)+1);
|
||||
}
|
||||
for(;;) {
|
||||
base_unsigned result =
|
||||
random::detail::subtract<base_result>()(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<base_unsigned>(range))
|
||||
return random::detail::add<base_unsigned, result_type>()(result, min_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<class It> 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<class It> void seed(It& first, It last)
|
||||
{
|
||||
_rng1.seed(first, last);
|
||||
|
||||
@@ -129,12 +129,61 @@ void instantiate_real_dist(URNG& urng, RealType /* ignored */)
|
||||
boost::gamma_distribution<RealType>(1));
|
||||
}
|
||||
|
||||
template<class URNG, class T>
|
||||
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<class T>
|
||||
void test_seed(boost::rand48 & urng, const T & t) {
|
||||
boost::rand48 urng2(t);
|
||||
urng2.seed(t);
|
||||
}
|
||||
|
||||
template<class URNG, class ResultType>
|
||||
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<char>(value));
|
||||
test_seed(urng, static_cast<signed char>(value));
|
||||
test_seed(urng, static_cast<unsigned char>(value));
|
||||
test_seed(urng, static_cast<short>(value));
|
||||
test_seed(urng, static_cast<unsigned short>(value));
|
||||
test_seed(urng, static_cast<int>(value));
|
||||
test_seed(urng, static_cast<unsigned int>(value));
|
||||
test_seed(urng, static_cast<long>(value));
|
||||
test_seed(urng, static_cast<unsigned long>(value));
|
||||
#if !defined(BOOST_NO_INT64_T)
|
||||
test_seed(urng, static_cast<boost::int64_t>(value));
|
||||
test_seed(urng, static_cast<boost::uint64_t>(value));
|
||||
#endif
|
||||
|
||||
// floating point types
|
||||
test_seed(urng, static_cast<float>(value));
|
||||
test_seed(urng, static_cast<double>(value));
|
||||
test_seed(urng, static_cast<long double>(value));
|
||||
}
|
||||
}
|
||||
|
||||
template<class URNG, class ResultType>
|
||||
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<int> v(9999u, 0x41);
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
<li><a href="#mersenne_twister">Class template
|
||||
<code>random::mersenne_twister</code></a></li>
|
||||
|
||||
<li><a href="#lagged_fibonacci">Class template
|
||||
<code>random::lagged_fibonacci</code></a></li>
|
||||
<li><a href="#lagged_fibonacci_01">Class template
|
||||
<code>random::lagged_fibonacci_01</code></a></li>
|
||||
|
||||
<li><a href="#performance">Performance</a></li>
|
||||
</ul>
|
||||
@@ -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
|
||||
</pre>
|
||||
|
||||
@@ -773,7 +773,7 @@ template<class T> void seed(T s)
|
||||
#include <<a href=
|
||||
"../../boost/random/inversive_congruential.hpp">boost/random/inversive_congruential.hpp</a>>
|
||||
|
||||
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;
|
||||
</pre>
|
||||
|
||||
<h3>Description</h3>
|
||||
@@ -812,7 +812,8 @@ typedef random::inversive_congruential<int32_t, 9102, 2147483647-36884165, 21
|
||||
|
||||
<p>The template parameter <code>IntType</code> shall denote a signed
|
||||
integral type large enough to hold p; a, b, and p are the parameters of the
|
||||
generators.</p>
|
||||
generators. The template parameter val is the validation value checked by
|
||||
validation.</p>
|
||||
|
||||
<p><em>Note:</em> 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 <<a href=
|
||||
"../../boost/random/mersenne_twister.hpp">boost/random/mersenne_twister.hpp</a>>
|
||||
|
||||
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)
|
||||
<p><strong>Effects:</strong> Constructs a <code>mersenne_twister</code> and
|
||||
calls <code>seed(gen)</code>.</p>
|
||||
|
||||
<p><em>Note:</em> When using direct-initialization syntax with an lvalue
|
||||
(e.g. in the variable definition <code>Gen gen2(gen);</code>), this
|
||||
templated constructor will be preferred over the compiler-generated copy
|
||||
constructor. For variable definitions which should copy the state of
|
||||
another <code>mersenne_twister</code>, use e.g. <code>Gen gen2 =
|
||||
gen;</code>, which is copy-initialization syntax and guaranteed to invoke
|
||||
the copy constructor.</p>
|
||||
<p><em>Note:</em> The copy constructor will always be preferred over the
|
||||
templated constructor. mersenne_twister takes special steps to guarantee
|
||||
this.</p>
|
||||
|
||||
<h3>Seeding</h3>
|
||||
<pre>
|
||||
@@ -953,39 +948,35 @@ template<class Generator> void seed(Generator & gen)
|
||||
<p><strong>Complexity:</strong> Exactly <code>n</code> invocations of
|
||||
<code>gen</code>.</p>
|
||||
|
||||
<p><em>Note:</em> When invoking <code>seed</code> with an lvalue, overload
|
||||
resolution chooses the function template unless the type of the argument
|
||||
exactly matches <code>result_type</code>. For other integer types, you
|
||||
should convert the argument to <code>result_type</code> explicitly.</p>
|
||||
|
||||
<h3><a name="mt11213b" id="mt11213b"></a><a name="mt19937" id=
|
||||
"mt19937">Specializations</a></h3>
|
||||
|
||||
<p>The specializations <code>mt11213b</code> and <code>mt19937</code> are
|
||||
from the paper cited above.</p>
|
||||
|
||||
<h2><a name="lagged_fibonacci" id="lagged_fibonacci">Class template
|
||||
<code>random::lagged_fibonacci</code></a></h2>
|
||||
<h2><a name="lagged_fibonacci_01" id="lagged_fibonacci_01">Class template
|
||||
<code>random::lagged_fibonacci_01</code></a></h2>
|
||||
|
||||
<h3>Synopsis</h3>
|
||||
<pre>
|
||||
#include <<a href=
|
||||
"../../boost/random/lagged_fibonacci.hpp">boost/random/lagged_fibonacci.hpp</a>>
|
||||
|
||||
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;
|
||||
</pre>
|
||||
|
||||
<h3>Description</h3>
|
||||
@@ -1029,22 +1020,22 @@ typedef random::lagged_fibonacci<double, 44497, 21034> lagged_fibonacci444
|
||||
|
||||
<h3>Constructors</h3>
|
||||
<pre>
|
||||
lagged_fibonacci()
|
||||
lagged_fibonacci_01()
|
||||
</pre>
|
||||
|
||||
<p><strong>Effects:</strong> Constructs a <code>lagged_fibonacci</code>
|
||||
<p><strong>Effects:</strong> Constructs a <code>lagged_fibonacci_01</code>
|
||||
generator and calls <code>seed()</code>.</p>
|
||||
<pre>
|
||||
explicit lagged_fibonacci(uint32_t value)
|
||||
explicit lagged_fibonacci_01(uint32_t value)
|
||||
</pre>
|
||||
|
||||
<p><strong>Effects:</strong> Constructs a <code>lagged_fibonacci</code>
|
||||
<p><strong>Effects:</strong> Constructs a <code>lagged_fibonacci_01</code>
|
||||
generator and calls <code>seed(value)</code>.</p>
|
||||
<pre>
|
||||
template<class Generator> explicit lagged_fibonacci(Generator & gen)
|
||||
template<class Generator> explicit lagged_fibonacci_01(Generator & gen)
|
||||
</pre>
|
||||
|
||||
<p><strong>Effects:</strong> Constructs a <code>lagged_fibonacci</code>
|
||||
<p><strong>Effects:</strong> Constructs a <code>lagged_fibonacci_01</code>
|
||||
generator and calls <code>seed(gen)</code>.</p>
|
||||
|
||||
<h3>Seeding</h3>
|
||||
@@ -1065,7 +1056,7 @@ template<class Generator> void seed(Generator & gen)
|
||||
</pre>
|
||||
|
||||
<p><strong>Effects:</strong> Sets the state of this
|
||||
<code>lagged_fibonacci</code> to the values returned by <code>p</code>
|
||||
<code>lagged_fibonacci_01</code> to the values returned by <code>p</code>
|
||||
invocations of <code>uniform_01<gen, FloatType></code>.<br>
|
||||
<strong>Complexity:</strong> Exactly <code>p</code> invocations of
|
||||
<code>gen</code>.</p>
|
||||
|
||||
@@ -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<double>(sum)/range;
|
||||
double threshold = 2*avg/std::sqrt(static_cast<double>(iter));
|
||||
double p = 1 / static_cast<double>(range);
|
||||
double threshold = 2*std::sqrt(static_cast<double>(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_two&, int_gen> level_three;
|
||||
level_three uint1_4(uint05, int_gen(1, 4));
|
||||
check_uniform_int(uint1_4, 100000);
|
||||
|
||||
typedef boost::uniform_int<boost::uint8_t> int8_gen;
|
||||
typedef boost::variate_generator<Generator&, int8_gen> 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<gen8_t, int8_gen> 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<gen8_t, int_gen> 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<result_type>::max BOOST_PREVENT_MACRO_SUBSTITUTION (); }
|
||||
result_type operator()() { return (max)()-1; }
|
||||
result_type operator()() { return state--; }
|
||||
private:
|
||||
result_type state;
|
||||
};
|
||||
|
||||
void test_overflow_range()
|
||||
|
||||
Reference in New Issue
Block a user