|
View:
New views
1 Messages
—
Rating Filter:
Alert me
|
|
|
[random] Seeding againAMDG
The attached patch allows random number generators to be seeded with any value. Currently linear_congruential and a few other generators can assert for some seeds. (For instance minstd_rand cannot be seeded with 0). For linear_congruential I am using the algorithm described in n2960, section 26.5.3.1/4. For linear_feedback_shift I use a similar idea, adding 2^(w-k) if the seed is less than 2^(w-k). The behavior of any code that was valid before, should be unaffected by this change. The patch includes test and documentation updates. The tests pass with gcc, msvc, and como. I think it's ready to go now. Okay to commit? In Christ, Steven Watanabe Index: boost/random/linear_feedback_shift.hpp =================================================================== --- boost/random/linear_feedback_shift.hpp (revision 57432) +++ boost/random/linear_feedback_shift.hpp (working copy) @@ -77,7 +77,12 @@ 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) Index: boost/random/linear_congruential.hpp =================================================================== --- boost/random/linear_congruential.hpp (revision 57432) +++ boost/random/linear_congruential.hpp (working copy) @@ -54,12 +54,9 @@ // BOOST_STATIC_ASSERT(m == 0 || c < m); explicit linear_congruential(IntType x0 = 1) - : _modulus(modulus), _x(_modulus ? (x0 % _modulus) : x0) + : _modulus(modulus) { - 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 @@ -77,8 +74,22 @@ // 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 += modulus; + } + // adjust to the correct range + if(increment == 0 && _x == 0) { + _x = 1; + } + assert(_x >= min()); + assert(_x <= max()); } template<class It> @@ -86,8 +97,7 @@ { 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; } @@ -261,7 +271,7 @@ 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)); } Index: libs/random/random-generators.html =================================================================== --- libs/random/random-generators.html (revision 57432) +++ libs/random/random-generators.html (working copy) @@ -495,11 +495,21 @@ </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> 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> + <p><strong>Effects:</strong> Changes the current value x(n) of the generator to <code>x0</code>.</p> @@ -605,8 +615,13 @@ 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,7 +660,16 @@ <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) </pre> @@ -655,6 +679,30 @@ 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 +1045,7 @@ <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 +1098,10 @@ <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> Index: libs/random/instantiate.cpp =================================================================== --- libs/random/instantiate.cpp (revision 57432) +++ libs/random/instantiate.cpp (working copy) @@ -133,53 +133,63 @@ 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> _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost |
| Free embeddable forum powered by Nabble | Forum Help |