mirror of
https://github.com/boostorg/random.git
synced 2026-01-19 04:22:17 +00:00
Allow arbitrary values to be used as seeds for linear_congruential, linear_feedback_shift, and any generators that depend on them. Fixes #3516
[SVN r57663]
This commit is contained in:
@@ -54,12 +54,8 @@ public:
|
||||
// BOOST_STATIC_ASSERT(m == 0 || c < m);
|
||||
|
||||
explicit linear_congruential(IntType x0 = 1)
|
||||
: _modulus(modulus), _x(_modulus ? (x0 % _modulus) : x0)
|
||||
{
|
||||
assert(c || x0); /* if c == 0 and x(0) == 0 then x(n) = 0 for all n */
|
||||
// overflow check
|
||||
// disabled because it gives spurious "divide by zero" gcc warnings
|
||||
// assert(m == 0 || (a*(m-1)+c) % m == (c < a ? c-a+m : c-a));
|
||||
seed(x0);
|
||||
|
||||
// MSVC fails BOOST_STATIC_ASSERT with std::numeric_limits at class scope
|
||||
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
||||
@@ -69,7 +65,6 @@ public:
|
||||
|
||||
template<class It>
|
||||
linear_congruential(It& first, It last)
|
||||
: _modulus(modulus)
|
||||
{
|
||||
seed(first, last);
|
||||
}
|
||||
@@ -77,8 +72,22 @@ public:
|
||||
// compiler-generated copy constructor and assignment operator are fine
|
||||
void seed(IntType x0 = 1)
|
||||
{
|
||||
assert(c || x0);
|
||||
_x = (_modulus ? (x0 % _modulus) : x0);
|
||||
// wrap _x if it doesn't fit in the destination
|
||||
if(modulus == 0) {
|
||||
_x = x0;
|
||||
} else {
|
||||
_x = x0 % modulus;
|
||||
}
|
||||
// handle negative seeds
|
||||
if(_x <= 0 && _x != 0) {
|
||||
_x += modulus;
|
||||
}
|
||||
// adjust to the correct range
|
||||
if(increment == 0 && _x == 0) {
|
||||
_x = 1;
|
||||
}
|
||||
assert(_x >= min());
|
||||
assert(_x <= max());
|
||||
}
|
||||
|
||||
template<class It>
|
||||
@@ -86,8 +95,7 @@ public:
|
||||
{
|
||||
if(first == last)
|
||||
throw std::invalid_argument("linear_congruential::seed");
|
||||
IntType value = *first++;
|
||||
_x = (_modulus ? (value % _modulus) : value);
|
||||
seed(*first++);
|
||||
}
|
||||
|
||||
result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return c == 0 ? 1 : 0; }
|
||||
@@ -137,8 +145,7 @@ public:
|
||||
private:
|
||||
#endif
|
||||
#endif
|
||||
|
||||
IntType _modulus; // work-around for gcc "divide by zero" warning in ctor
|
||||
|
||||
IntType _x;
|
||||
};
|
||||
|
||||
@@ -261,7 +268,7 @@ private:
|
||||
if(sizeof(T) < sizeof(uint64_t)) {
|
||||
return (static_cast<uint64_t>(x) << 16) | 0x330e;
|
||||
} else {
|
||||
return(static_cast<uint64_t>(x));
|
||||
return(static_cast<uint64_t>(x));
|
||||
}
|
||||
}
|
||||
static uint64_t cnv(float x) { return(static_cast<uint64_t>(x)); }
|
||||
|
||||
@@ -77,7 +77,12 @@ public:
|
||||
seed(first, last);
|
||||
}
|
||||
|
||||
void seed(UIntType s0 = 341) { assert(s0 >= (1 << (w-k))); value = s0; }
|
||||
void seed(UIntType s0 = 341) {
|
||||
if(s0 < (1 << (w-k))) {
|
||||
s0 += 1 << (w-k);
|
||||
}
|
||||
value = s0;
|
||||
}
|
||||
template<class It> void seed(It& first, It last)
|
||||
{
|
||||
if(first == last)
|
||||
|
||||
@@ -133,53 +133,63 @@ 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);
|
||||
template<class URNG, class T, class Converted>
|
||||
void test_seed_conversion(URNG & urng, const T & t, const Converted &) {
|
||||
Converted c = static_cast<Converted>(t);
|
||||
if(static_cast<T>(c) == t) {
|
||||
URNG urng2(c);
|
||||
BOOST_CHECK_MESSAGE(urng == urng2, std::string("Testing seed constructor: ") + typeid(Converted).name());
|
||||
urng2.seed(c);
|
||||
BOOST_CHECK(urng == urng2);
|
||||
}
|
||||
}
|
||||
|
||||
// rand48 uses non-standard seeding
|
||||
template<class T>
|
||||
void test_seed(boost::rand48 & urng, const T & t) {
|
||||
template<class T, class Converted>
|
||||
void test_seed_conversion(boost::rand48 & urng, const T & t, const Converted &) {
|
||||
boost::rand48 urng2(t);
|
||||
urng2.seed(t);
|
||||
}
|
||||
|
||||
template<class URNG, class ResultType>
|
||||
void instantiate_seed(const URNG &, const ResultType &) {
|
||||
void test_seed(const URNG &, const ResultType & v) {
|
||||
typename URNG::result_type value = static_cast<typename URNG::result_type>(v);
|
||||
|
||||
URNG urng(value);
|
||||
|
||||
// integral types
|
||||
test_seed_conversion(urng, value, static_cast<char>(0));
|
||||
test_seed_conversion(urng, value, static_cast<signed char>(0));
|
||||
test_seed_conversion(urng, value, static_cast<unsigned char>(0));
|
||||
test_seed_conversion(urng, value, static_cast<short>(0));
|
||||
test_seed_conversion(urng, value, static_cast<unsigned short>(0));
|
||||
test_seed_conversion(urng, value, static_cast<int>(0));
|
||||
test_seed_conversion(urng, value, static_cast<unsigned int>(0));
|
||||
test_seed_conversion(urng, value, static_cast<long>(0));
|
||||
test_seed_conversion(urng, value, static_cast<unsigned long>(0));
|
||||
#if !defined(BOOST_NO_INT64_T)
|
||||
test_seed_conversion(urng, value, static_cast<boost::int64_t>(0));
|
||||
test_seed_conversion(urng, value, static_cast<boost::uint64_t>(0));
|
||||
#endif
|
||||
|
||||
// floating point types
|
||||
test_seed_conversion(urng, value, static_cast<float>(0));
|
||||
test_seed_conversion(urng, value, static_cast<double>(0));
|
||||
test_seed_conversion(urng, value, static_cast<long double>(0));
|
||||
}
|
||||
|
||||
template<class URNG, class ResultType>
|
||||
void instantiate_seed(const URNG & 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));
|
||||
}
|
||||
test_seed(urng, 0);
|
||||
test_seed(urng, 127);
|
||||
test_seed(urng, 539157235);
|
||||
test_seed(urng, ~0u);
|
||||
}
|
||||
|
||||
template<class URNG, class ResultType>
|
||||
|
||||
@@ -495,13 +495,20 @@ explicit linear_congruential(IntType x0 = 1)
|
||||
</pre>
|
||||
|
||||
<p><strong>Effects:</strong> Constructs a <code>linear_congruential</code>
|
||||
generator with x(0) := <code>x0</code>.</p>
|
||||
generator, seeding it with <code>x0</code>.</p>
|
||||
|
||||
<pre>
|
||||
void seed(IntType x0)
|
||||
</pre>
|
||||
|
||||
<p><strong>Effects:</strong> Changes the current value x(n) of the
|
||||
generator to <code>x0</code>.</p>
|
||||
|
||||
<p><strong>Effects:</strong> If <code>c</code> mod <code>m</code> is zero
|
||||
and <code>x0</code> mod <code>m</code> is zero, changes the current value of
|
||||
the generator to 1. Otherwise, changes it to <code>x0</code> mod
|
||||
<code>m</code>. If <code>c</code> is zero, distinct seeds in the range
|
||||
[1,m) will leave the generator in distinct states. If <code>c</code>
|
||||
is not zero, the range is [0,m).
|
||||
</p>
|
||||
|
||||
<h3><a name="minstd_rand" id="minstd_rand">Specializations</a></h3>
|
||||
|
||||
@@ -605,8 +612,13 @@ public:
|
||||
static const result_type min_value = 1;
|
||||
static const result_type max_value = MLCG1::max_value-1;
|
||||
additive_combine();
|
||||
additive_combine(typename MLCG1::result_type seed);
|
||||
additive_combine(typename MLCG1::result_type seed1,
|
||||
typename MLCG2::result_type seed2);
|
||||
void seed();
|
||||
void seed(typename MLCG1::result_type seed);
|
||||
void seed(typename MLCG1::result_type seed1,
|
||||
typename MLCG2::result_type seed2);
|
||||
result_type operator()();
|
||||
bool validation(result_type x) const;
|
||||
};
|
||||
@@ -645,6 +657,15 @@ additive_combine()
|
||||
|
||||
<p><strong>Effects:</strong> Constructs an <code>additive_combine</code>
|
||||
generator using the default constructors of the two base generators.</p>
|
||||
|
||||
<pre>
|
||||
additive_combine(typename MLCG1::result_type seed)
|
||||
</pre>
|
||||
|
||||
<p><strong>Effects:</strong> Constructs an <code>additive_combine</code>
|
||||
generator, using <code>seed</code> as the constructor argument for
|
||||
both base generators.</p>
|
||||
|
||||
<pre>
|
||||
additive_combine(typename MLCG1::result_type seed1,
|
||||
typename MLCG2::result_type seed2)
|
||||
@@ -655,6 +676,30 @@ additive_combine(typename MLCG1::result_type seed1,
|
||||
constructor argument to the first and second base generator,
|
||||
respectively.</p>
|
||||
|
||||
<pre>
|
||||
void seed()
|
||||
</pre>
|
||||
|
||||
<p><strong>Effects:</strong> Seeds an <code>additive_combine</code>
|
||||
generator using the default seeds of the two base generators.</p>
|
||||
|
||||
<pre>
|
||||
void seed(typename MLCG1::result_type seed)
|
||||
</pre>
|
||||
|
||||
<p><strong>Effects:</strong> Seeds an <code>additive_combine</code>
|
||||
generator, using <code>seed</code> as the seed for both base
|
||||
generators.</p>
|
||||
|
||||
<pre>
|
||||
void seed(typename MLCG1::result_type seed1,
|
||||
typename MLCG2::result_type seed2)
|
||||
</pre>
|
||||
|
||||
<p><strong>Effects:</strong> Seeds an <code>additive_combine</code>
|
||||
generator, using <code>seed1</code> and <code>seed2</code> as the
|
||||
seeds to the first and second base generator, respectively.</p>
|
||||
|
||||
<h3><a name="ecuyer1988" id="ecuyer1988">Specialization</a></h3>
|
||||
|
||||
<p>The specialization <code>ecuyer1988</code> was suggested in the above
|
||||
@@ -997,7 +1042,7 @@ typedef random::lagged_fibonacci_01<double, 48, 44497, 21034> lagged_fibon
|
||||
|
||||
<h3>Description</h3>
|
||||
|
||||
<p>Instantiations of class template <code>lagged_fibonacci</code> model a
|
||||
<p>Instantiations of class template <code>lagged_fibonacci_01</code> model a
|
||||
<a href="random-concepts.html#pseudo-rng">pseudo-random number
|
||||
generator</a>. It uses a lagged Fibonacci algorithm with two lags p and q,
|
||||
evaluated in floating-point arithmetic: x(i) = x(i-p) + x(i-q) (mod 1) with
|
||||
@@ -1050,7 +1095,10 @@ void seed(uint32_t value)
|
||||
|
||||
<p><strong>Effects:</strong> Constructs a <code>minstd_rand0</code>
|
||||
generator with the constructor parameter <code>value</code> and calls
|
||||
<code>seed</code> with it.</p>
|
||||
<code>seed</code> with it. Distinct seeds in the range [1, 2147483647)
|
||||
will produce generators with different states. Other seeds will be
|
||||
equivalent to some seed within this range. See
|
||||
<a href="#linear_congruential">linear_congruential</a> for details.</p>
|
||||
<pre>
|
||||
template<class Generator> void seed(Generator & gen)
|
||||
</pre>
|
||||
|
||||
Reference in New Issue
Block a user