|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r50312 - in trunk: boost/random libs/random
From: marshall_at_[hidden]
Date: 2008-12-17 21:37:09
Author: marshall
Date: 2008-12-17 21:37:07 EST (Wed, 17 Dec 2008)
New Revision: 50312
URL: http://svn.boost.org/trac/boost/changeset/50312
Log:
Applied patch from bug #1546
Text files modified:
trunk/boost/random/uniform_int.hpp | 103 +++++++++++++++++++++++----------------
trunk/libs/random/random_test.cpp | 67 ++++++++++++++++++++++++++
2 files changed, 128 insertions(+), 42 deletions(-)
Modified: trunk/boost/random/uniform_int.hpp
==============================================================================
--- trunk/boost/random/uniform_int.hpp (original)
+++ trunk/boost/random/uniform_int.hpp 2008-12-17 21:37:07 EST (Wed, 17 Dec 2008)
@@ -60,6 +60,49 @@
template<class Engine>
result_type operator()(Engine& eng)
{
+ return generate(eng, _min, _max, _range);
+ }
+
+ template<class Engine>
+ result_type operator()(Engine& eng, result_type n)
+ {
+ assert(n > 0);
+
+ if (n == 1)
+ {
+ return 0;
+ }
+
+ return generate(eng, 0, n - 1, n - 1);
+ }
+
+#if !defined(BOOST_NO_OPERATORS_IN_NAMESPACE) && !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
+ template<class CharT, class Traits>
+ friend std::basic_ostream<CharT,Traits>&
+ operator<<(std::basic_ostream<CharT,Traits>& os, const uniform_int& ud)
+ {
+ os << ud._min << " " << ud._max;
+ return os;
+ }
+
+ template<class CharT, class Traits>
+ friend std::basic_istream<CharT,Traits>&
+ operator>>(std::basic_istream<CharT,Traits>& is, uniform_int& ud)
+ {
+# if BOOST_WORKAROUND(_MSC_FULL_VER, BOOST_TESTED_AT(13102292)) && BOOST_MSVC == 1400
+ return detail::extract_uniform_int(is, ud, ud.impl);
+# else
+ is >> std::ws >> ud._min >> std::ws >> ud._max;
+ ud.init();
+ return is;
+# endif
+ }
+#endif
+
+private:
+ template<class Engine>
+ static result_type generate(Engine& eng, result_type min_value, result_type max_value, range_type range)
+ {
typedef typename Engine::result_type base_result;
// ranges are always unsigned
typedef typename make_unsigned<base_result>::type base_unsigned;
@@ -67,25 +110,25 @@
const base_unsigned brange =
random::detail::subtract<base_result>()((eng.max)(), (eng.min)());
- if(_range == 0) {
- return _min;
- } else if(brange == _range) {
+ if(range == 0) {
+ return min_value;
+ } else if(brange == range) {
// this will probably never happen in real life
// basically nothing to do; just take care we don't overflow / underflow
base_unsigned v = random::detail::subtract<base_result>()(eng(), bmin);
- return random::detail::add<base_unsigned, result_type>()(v, _min);
- } else if(brange < _range) {
+ return random::detail::add<base_unsigned, result_type>()(v, min_value);
+ } else if(brange < range) {
// use rejection method to handle things like 0..3 --> 0..4
for(;;) {
// concatenate several invocations of the base RNG
// take extra care to avoid overflows
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 == (std::numeric_limits<range_type>::max)()) {
+ limit = range/(range_type(brange)+1);
+ if(range % range_type(brange)+1 == range_type(brange))
++limit;
} else {
- limit = (_range+1)/(range_type(brange)+1);
+ 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
@@ -96,18 +139,18 @@
mult *= range_type(brange)+range_type(1);
}
if(mult == limit)
- // _range+1 is an integer power of brange+1: no rejections required
+ // range+1 is an integer power of brange+1: no rejections required
return result;
- // _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);
+ // 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);
}
} else { // brange > range
- if(brange / _range > 4 /* quantization_cutoff */ ) {
+ 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, _max)(eng);
+ return boost::uniform_smallint<result_type>(min_value, max_value)(eng);
} else {
// use rejection method to handle cases like 0..5 -> 0..4
for(;;) {
@@ -115,37 +158,13 @@
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);
+ if(result <= static_cast<base_unsigned>(range))
+ return random::detail::add<base_unsigned, result_type>()(result, min_value);
}
}
}
}
-#if !defined(BOOST_NO_OPERATORS_IN_NAMESPACE) && !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
- template<class CharT, class Traits>
- friend std::basic_ostream<CharT,Traits>&
- operator<<(std::basic_ostream<CharT,Traits>& os, const uniform_int& ud)
- {
- os << ud._min << " " << ud._max;
- return os;
- }
-
- template<class CharT, class Traits>
- friend std::basic_istream<CharT,Traits>&
- operator>>(std::basic_istream<CharT,Traits>& is, uniform_int& ud)
- {
-# if BOOST_WORKAROUND(_MSC_FULL_VER, BOOST_TESTED_AT(13102292)) && BOOST_MSVC == 1400
- return detail::extract_uniform_int(is, ud, ud.impl);
-# else
- is >> std::ws >> ud._min >> std::ws >> ud._max;
- ud.init();
- return is;
-# endif
- }
-#endif
-
-private:
void init()
{
_range = random::detail::subtract<result_type>()(_max, _min);
Modified: trunk/libs/random/random_test.cpp
==============================================================================
--- trunk/libs/random/random_test.cpp (original)
+++ trunk/libs/random/random_test.cpp 2008-12-17 21:37:07 EST (Wed, 17 Dec 2008)
@@ -500,6 +500,72 @@
{ }
#endif
+template <typename EngineT>
+struct rand_for_random_shuffle
+{
+ explicit rand_for_random_shuffle(EngineT &engine)
+ : m_engine(engine)
+ { }
+
+ template <typename IntT>
+ IntT operator()(IntT upperBound)
+ {
+ assert(upperBound > 0);
+
+ if (upperBound == 1)
+ {
+ return 0;
+ }
+
+ typedef boost::uniform_int<IntT> distribution_type;
+ typedef boost::variate_generator<EngineT &, distribution_type> generator_type;
+
+ return generator_type(m_engine, distribution_type(0, upperBound - 1))();
+ }
+
+ EngineT &m_engine;
+
+};
+
+// Test that uniform_int<> can be used with std::random_shuffle
+// Author: Jos Hickson
+void test_random_shuffle()
+{
+ typedef boost::uniform_int<> distribution_type;
+ typedef boost::variate_generator<boost::mt19937 &, distribution_type> generator_type;
+
+ boost::mt19937 engine1(1234);
+ boost::mt19937 engine2(1234);
+
+ rand_for_random_shuffle<boost::mt19937> referenceRand(engine1);
+
+ distribution_type dist(0,10);
+ generator_type testRand(engine2, dist);
+
+ std::vector<int> referenceVec;
+
+ for (int i = 0; i < 200; ++i)
+ {
+ referenceVec.push_back(i);
+ }
+
+ std::vector<int> testVec(referenceVec);
+
+ std::random_shuffle(referenceVec.begin(), referenceVec.end(), referenceRand);
+ std::random_shuffle(testVec.begin(), testVec.end(), testRand);
+
+ typedef std::vector<int>::iterator iter_type;
+ iter_type theEnd(referenceVec.end());
+
+ for (iter_type referenceIter(referenceVec.begin()), testIter(testVec.begin());
+ referenceIter != theEnd;
+ ++referenceIter, ++testIter)
+ {
+ BOOST_CHECK_EQUAL(*referenceIter, *testIter);
+ }
+}
+
+
int test_main(int, char*[])
{
@@ -528,6 +594,7 @@
<< std::endl;
test_overflow_range();
+ test_random_shuffle();
return 0;
#else
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk