| 1 | /* boost random_test.cpp various tests | 
|---|
| 2 |  * | 
|---|
| 3 |  * Copyright Jens Maurer 2000 | 
|---|
| 4 |  * Distributed under the Boost Software License, Version 1.0. (See | 
|---|
| 5 |  * accompanying file LICENSE_1_0.txt or copy at | 
|---|
| 6 |  * http://www.boost.org/LICENSE_1_0.txt) | 
|---|
| 7 |  * | 
|---|
| 8 |  * $Id: random_test.cpp,v 1.58 2005/08/25 16:27:27 johnmaddock Exp $ | 
|---|
| 9 |  */ | 
|---|
| 10 |  | 
|---|
| 11 | #if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 | 
|---|
| 12 | #pragma warning( disable : 4786 ) | 
|---|
| 13 | #endif | 
|---|
| 14 |  | 
|---|
| 15 | #include <iostream> | 
|---|
| 16 | #include <sstream> | 
|---|
| 17 | #include <string> | 
|---|
| 18 | #include <cmath> | 
|---|
| 19 | #include <iterator> | 
|---|
| 20 | #include <vector> | 
|---|
| 21 | #include <boost/random.hpp> | 
|---|
| 22 | #include <boost/config.hpp> | 
|---|
| 23 |  | 
|---|
| 24 | #include <boost/test/test_tools.hpp> | 
|---|
| 25 | #include <boost/test/included/test_exec_monitor.hpp> | 
|---|
| 26 |  | 
|---|
| 27 | #ifdef BOOST_NO_STDC_NAMESPACE | 
|---|
| 28 |   namespace std { using ::abs; using ::fabs; using ::pow; } | 
|---|
| 29 | #endif | 
|---|
| 30 |  | 
|---|
| 31 |  | 
|---|
| 32 | /* | 
|---|
| 33 |  * General portability note: | 
|---|
| 34 |  * MSVC mis-compiles explicit function template instantiations. | 
|---|
| 35 |  * For example, f<A>() and f<B>() are both compiled to call f<A>(). | 
|---|
| 36 |  * BCC is unable to implicitly convert a "const char *" to a std::string | 
|---|
| 37 |  * when using explicit function template instantiations. | 
|---|
| 38 |  * | 
|---|
| 39 |  * Therefore, avoid explicit function template instantiations. | 
|---|
| 40 |  */ | 
|---|
| 41 |  | 
|---|
| 42 | /* | 
|---|
| 43 |  * Validate correct implementation | 
|---|
| 44 |  */ | 
|---|
| 45 |  | 
|---|
| 46 | // own run | 
|---|
| 47 | bool check(unsigned long x, const boost::mt11213b&) { return x == 3809585648U; } | 
|---|
| 48 |  | 
|---|
| 49 | // validation by experiment from mt19937.c | 
|---|
| 50 | bool check(unsigned long x, const boost::mt19937&) { return x == 4123659995U; } | 
|---|
| 51 |  | 
|---|
| 52 | // validation values from the publications | 
|---|
| 53 | bool check(int x, const boost::minstd_rand0&) { return x == 1043618065; } | 
|---|
| 54 |  | 
|---|
| 55 | // validation values from the publications | 
|---|
| 56 | bool check(int x, const boost::minstd_rand&) { return x == 399268537; } | 
|---|
| 57 |  | 
|---|
| 58 | #if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) | 
|---|
| 59 | // by experiment from lrand48() | 
|---|
| 60 | bool check(unsigned long x, const boost::rand48&) { return x == 1993516219; } | 
|---|
| 61 | #endif | 
|---|
| 62 |  | 
|---|
| 63 | // ???? | 
|---|
| 64 | bool check(unsigned long x, const boost::taus88&) { return x == 3535848941U; } | 
|---|
| 65 |  | 
|---|
| 66 | // ???? | 
|---|
| 67 | bool check(int x, const boost::ecuyer1988&) { return x == 2060321752; } | 
|---|
| 68 |  | 
|---|
| 69 | // validation by experiment from Harry Erwin's generator.h (private e-mail) | 
|---|
| 70 | bool check(unsigned int x, const boost::kreutzer1986&) { return x == 139726; } | 
|---|
| 71 |  | 
|---|
| 72 | bool check(double x, const boost::lagged_fibonacci607&) { return std::abs(x-0.401269) < 1e-5; } | 
|---|
| 73 |  | 
|---|
| 74 | // principal operation validated with CLHEP, values by experiment | 
|---|
| 75 | bool check(unsigned long x, const boost::ranlux3&) { return x == 5957620; } | 
|---|
| 76 | bool check(unsigned long x, const boost::ranlux4&) { return x == 8587295; } | 
|---|
| 77 |  | 
|---|
| 78 | bool check(float x, const boost::ranlux3_01&) | 
|---|
| 79 | { return std::abs(x-5957620/std::pow(2.0f,24)) < 1e-6; } | 
|---|
| 80 | bool check(float x, const boost::ranlux4_01&) | 
|---|
| 81 | { return std::abs(x-8587295/std::pow(2.0f,24)) < 1e-6; } | 
|---|
| 82 |  | 
|---|
| 83 | bool check(double x, const boost::ranlux64_3_01&) | 
|---|
| 84 | { return std::abs(x-0.838413) < 1e-6; } | 
|---|
| 85 | bool check(double x, const boost::ranlux64_4_01&) | 
|---|
| 86 | { return std::abs(x-0.59839) < 1e-6; } | 
|---|
| 87 |  | 
|---|
| 88 | template<class PRNG> | 
|---|
| 89 | void validate(const std::string & name, const PRNG &) | 
|---|
| 90 | { | 
|---|
| 91 |   std::cout << "validating " << name << ": "; | 
|---|
| 92 |   PRNG rng;  // default ctor | 
|---|
| 93 |   for(int i = 0; i < 9999; i++) | 
|---|
| 94 |     rng(); | 
|---|
| 95 |   typename PRNG::result_type val = rng(); | 
|---|
| 96 |   // make sure the validation function is a static member | 
|---|
| 97 |   bool result = check(val, rng); | 
|---|
| 98 |    | 
|---|
| 99 |   // allow for a simple eyeball check for MSVC instantiation brokenness | 
|---|
| 100 |   // (if the numbers for all generators are the same, it's obviously broken) | 
|---|
| 101 |   std::cout << val << std::endl; | 
|---|
| 102 |   BOOST_CHECK(result); | 
|---|
| 103 | } | 
|---|
| 104 |  | 
|---|
| 105 | void validate_all() | 
|---|
| 106 | { | 
|---|
| 107 |   using namespace boost; | 
|---|
| 108 | #if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) | 
|---|
| 109 |   validate("rand48", rand48()); | 
|---|
| 110 | #endif | 
|---|
| 111 |   validate("minstd_rand", minstd_rand()); | 
|---|
| 112 |   validate("minstd_rand0", minstd_rand0()); | 
|---|
| 113 |   validate("ecuyer combined", ecuyer1988()); | 
|---|
| 114 |   validate("mt11213b", mt11213b()); | 
|---|
| 115 |   validate("mt19937", mt19937()); | 
|---|
| 116 |   validate("kreutzer1986", kreutzer1986()); | 
|---|
| 117 |   validate("ranlux3", ranlux3()); | 
|---|
| 118 |   validate("ranlux4", ranlux4()); | 
|---|
| 119 |   validate("ranlux3_01", ranlux3_01()); | 
|---|
| 120 |   validate("ranlux4_01", ranlux4_01()); | 
|---|
| 121 |   validate("ranlux64_3_01", ranlux64_3_01()); | 
|---|
| 122 |   validate("ranlux64_4_01", ranlux64_4_01()); | 
|---|
| 123 |   validate("taus88", taus88()); | 
|---|
| 124 |   validate("lagged_fibonacci607", lagged_fibonacci607()); | 
|---|
| 125 | } | 
|---|
| 126 |  | 
|---|
| 127 |  | 
|---|
| 128 | /* | 
|---|
| 129 |  * Check function signatures | 
|---|
| 130 |  */ | 
|---|
| 131 |  | 
|---|
| 132 | #if BOOST_WORKAROUND( __BORLANDC__, BOOST_TESTED_AT( 0x570) ) | 
|---|
| 133 | #pragma warn -par | 
|---|
| 134 | #endif | 
|---|
| 135 | template<class URNG, class Dist> | 
|---|
| 136 | void instantiate_dist(URNG& urng, const char * name, const Dist& dist) | 
|---|
| 137 | { | 
|---|
| 138 |   // this makes a copy of urng | 
|---|
| 139 |   boost::variate_generator<URNG, Dist> gen(urng, dist); | 
|---|
| 140 |  | 
|---|
| 141 |   // this keeps a reference to urng | 
|---|
| 142 |   boost::variate_generator<URNG&, Dist> genref(urng, dist); | 
|---|
| 143 |  | 
|---|
| 144 | #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | 
|---|
| 145 |   // and here is a pointer to (a copy of) the urng | 
|---|
| 146 |   URNG copy = urng; | 
|---|
| 147 |   boost::variate_generator<URNG*, Dist> genptr(©, dist); | 
|---|
| 148 | #endif | 
|---|
| 149 |  | 
|---|
| 150 |   for(int i = 0; i < 1000; ++i) { | 
|---|
| 151 |     (void) gen(); | 
|---|
| 152 |     (void) genref(); | 
|---|
| 153 | #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | 
|---|
| 154 |     (void) genptr(); | 
|---|
| 155 | #endif | 
|---|
| 156 |   } | 
|---|
| 157 |   typename Dist::result_type g = gen(); | 
|---|
| 158 |   BOOST_CHECK(std::abs(g - genref()) < 1e-6); | 
|---|
| 159 | #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | 
|---|
| 160 |   BOOST_CHECK(std::abs(g - genptr()) < 1e-6); | 
|---|
| 161 | #endif | 
|---|
| 162 |  | 
|---|
| 163 |   (void) gen.engine(); | 
|---|
| 164 |   gen.distribution().reset(); | 
|---|
| 165 |  | 
|---|
| 166 |   Dist d = dist;            // copy ctor | 
|---|
| 167 |   d = dist;                 // copy assignment | 
|---|
| 168 |  | 
|---|
| 169 | #if !defined(BOOST_NO_OPERATORS_IN_NAMESPACE) && !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) | 
|---|
| 170 |   { | 
|---|
| 171 |     std::ostringstream file; | 
|---|
| 172 |     file << urng << std::endl; | 
|---|
| 173 |     file << d; | 
|---|
| 174 |     std::istringstream input(file.str()); | 
|---|
| 175 |     // std::cout << file.str() << std::endl; | 
|---|
| 176 |     URNG restored_engine; | 
|---|
| 177 |     input >> restored_engine; | 
|---|
| 178 |     input >> std::ws; | 
|---|
| 179 |     Dist restored_dist; | 
|---|
| 180 |     input >> restored_dist; | 
|---|
| 181 | #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // MSVC brokenness | 
|---|
| 182 |     boost::variate_generator<URNG, Dist> old(urng, d); | 
|---|
| 183 |     boost::variate_generator<URNG, Dist> restored(restored_engine, restored_dist); | 
|---|
| 184 |     // advance some more so that state is exercised | 
|---|
| 185 |     for(int i = 0; i < 1000; ++i) { | 
|---|
| 186 |       (void) old(); | 
|---|
| 187 |       (void) restored(); | 
|---|
| 188 |     } | 
|---|
| 189 |     BOOST_CHECK_MESSAGE((std::abs(old()-restored()) < 0.0001), | 
|---|
| 190 |                         (std::string(name) + " old == restored_dist")); | 
|---|
| 191 | #endif // BOOST_MSVC | 
|---|
| 192 |   } | 
|---|
| 193 | #endif // BOOST_NO_OPERATORS_IN_NAMESPACE | 
|---|
| 194 | } | 
|---|
| 195 |  | 
|---|
| 196 | template<class URNG, class RealType> | 
|---|
| 197 | void instantiate_real_dist(URNG& urng, RealType /* ignored */) | 
|---|
| 198 | { | 
|---|
| 199 |   instantiate_dist(urng, "uniform_real", | 
|---|
| 200 |                    boost::uniform_real<RealType>(0, 2.1)); | 
|---|
| 201 |   instantiate_dist(urng, "triangle_distribution", | 
|---|
| 202 |                    boost::triangle_distribution<RealType>(1, 1.5, 7)); | 
|---|
| 203 |   instantiate_dist(urng, "exponential_distribution", | 
|---|
| 204 |                    boost::exponential_distribution<RealType>(5)); | 
|---|
| 205 |   instantiate_dist(urng, "normal_distribution", | 
|---|
| 206 |                    boost::normal_distribution<RealType>()); | 
|---|
| 207 |   instantiate_dist(urng, "lognormal_distribution", | 
|---|
| 208 |                    boost::lognormal_distribution<RealType>(1, 1)); | 
|---|
| 209 |   instantiate_dist(urng, "cauchy_distribution", | 
|---|
| 210 |                    boost::cauchy_distribution<RealType>(1)); | 
|---|
| 211 |   instantiate_dist(urng, "gamma_distribution", | 
|---|
| 212 |                    boost::gamma_distribution<RealType>(1)); | 
|---|
| 213 | } | 
|---|
| 214 |  | 
|---|
| 215 | template<class URNG, class ResultType> | 
|---|
| 216 | void instantiate_urng(const std::string & s, const URNG &, const ResultType &) | 
|---|
| 217 | { | 
|---|
| 218 |   std::cout << "Basic tests for " << s; | 
|---|
| 219 |   URNG urng; | 
|---|
| 220 |   urng.seed();                                  // seed() member function | 
|---|
| 221 |   int a[URNG::has_fixed_range ? 5 : 10];        // compile-time constant | 
|---|
| 222 |   (void) a;   // avoid "unused" warning | 
|---|
| 223 |   typename URNG::result_type x1 = urng(); | 
|---|
| 224 |   ResultType x2 = x1; | 
|---|
| 225 |   (void) &x2;           // avoid "unused" warning | 
|---|
| 226 |  | 
|---|
| 227 |   URNG urng2 = urng;             // copy constructor | 
|---|
| 228 | #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // MSVC brokenness | 
|---|
| 229 |   BOOST_CHECK(urng == urng2);     // operator== | 
|---|
| 230 |   BOOST_CHECK(!(urng != urng2));  // operator!= | 
|---|
| 231 |   urng(); | 
|---|
| 232 |   urng2 = urng;                  // copy assignment | 
|---|
| 233 |   BOOST_CHECK(urng == urng2); | 
|---|
| 234 | #endif // BOOST_MSVC | 
|---|
| 235 |  | 
|---|
| 236 |   const std::vector<int> v(9999u, 0x41); | 
|---|
| 237 |   std::vector<int>::const_iterator it = v.begin(); | 
|---|
| 238 |   std::vector<int>::const_iterator it_end = v.end(); | 
|---|
| 239 |   URNG urng3(it, it_end); | 
|---|
| 240 |   BOOST_CHECK(it != v.begin()); | 
|---|
| 241 |   std::cout << "; seeding uses " << (it - v.begin()) << " words" << std::endl; | 
|---|
| 242 |  | 
|---|
| 243 |   bool have_exception = false; | 
|---|
| 244 |   try { | 
|---|
| 245 |     // now check that exceptions are thrown | 
|---|
| 246 |     it = v.end(); | 
|---|
| 247 |     urng3.seed(it, it_end); | 
|---|
| 248 |   } catch(std::invalid_argument& x) { | 
|---|
| 249 |     have_exception = true; | 
|---|
| 250 |   } | 
|---|
| 251 |   BOOST_CHECK(have_exception); | 
|---|
| 252 |  | 
|---|
| 253 |   // check for min/max members | 
|---|
| 254 |   ResultType min = (urng3.min)(); | 
|---|
| 255 |   (void) &min; | 
|---|
| 256 |   ResultType max = (urng3.max)(); | 
|---|
| 257 |   (void) &max; | 
|---|
| 258 |  | 
|---|
| 259 | #if !defined(BOOST_NO_OPERATORS_IN_NAMESPACE) && !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) | 
|---|
| 260 |   // Streamable concept not supported for broken compilers | 
|---|
| 261 |  | 
|---|
| 262 |   // advance a little so that state is relatively arbitrary | 
|---|
| 263 |   for(int i = 0; i < 9307; ++i) | 
|---|
| 264 |     urng(); | 
|---|
| 265 |   urng2 = urng; | 
|---|
| 266 |  | 
|---|
| 267 |   { | 
|---|
| 268 |     // narrow stream first | 
|---|
| 269 |     std::ostringstream file; | 
|---|
| 270 |     file << urng; | 
|---|
| 271 |     // move forward | 
|---|
| 272 |     urng(); | 
|---|
| 273 |     // restore old state | 
|---|
| 274 |     std::istringstream input(file.str()); | 
|---|
| 275 |     input >> urng; | 
|---|
| 276 |     // std::cout << file.str() << std::endl; | 
|---|
| 277 | #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // MSVC brokenness | 
|---|
| 278 |     // advance some more so that state is exercised | 
|---|
| 279 |     for(int i = 0; i < 10000; ++i) { | 
|---|
| 280 |       urng(); | 
|---|
| 281 |       urng2(); | 
|---|
| 282 |     } | 
|---|
| 283 |     BOOST_CHECK(urng == urng2); | 
|---|
| 284 | #endif // BOOST_MSVC | 
|---|
| 285 |   } | 
|---|
| 286 |    | 
|---|
| 287 |   urng2 = urng; | 
|---|
| 288 | #if !defined(BOOST_NO_STD_WSTREAMBUF) && !defined(BOOST_NO_STD_WSTRING) | 
|---|
| 289 |   { | 
|---|
| 290 |     // then wide stream | 
|---|
| 291 |     std::wostringstream file; | 
|---|
| 292 |     file << urng; | 
|---|
| 293 |     // move forward | 
|---|
| 294 |     urng(); | 
|---|
| 295 |     std::wistringstream input(file.str()); | 
|---|
| 296 |     input >> urng; | 
|---|
| 297 | #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // MSVC brokenness | 
|---|
| 298 |     // advance some more so that state is exercised | 
|---|
| 299 |     for(int i = 0; i < 10000; ++i) { | 
|---|
| 300 |       urng(); | 
|---|
| 301 |       urng2(); | 
|---|
| 302 |     } | 
|---|
| 303 |     BOOST_CHECK(urng == urng2); | 
|---|
| 304 | #endif // BOOST_MSVC | 
|---|
| 305 |   } | 
|---|
| 306 | #endif // BOOST_NO_STD_WSTREAMBUF, BOOST_NO_STD_WSTRING | 
|---|
| 307 | #endif // BOOST_NO_OPERATORS_IN_NAMESPACE etc. | 
|---|
| 308 |  | 
|---|
| 309 |   // instantiate various distributions with this URNG | 
|---|
| 310 |   // instantiate_dist(urng, "uniform_smallint", boost::uniform_smallint(0, 11)); | 
|---|
| 311 |   instantiate_dist(urng, "uniform_int", boost::uniform_int<>(-200, 20000)); | 
|---|
| 312 |   instantiate_dist(urng, "bernoulli_distribution", | 
|---|
| 313 |                    boost::bernoulli_distribution<>(0.2)); | 
|---|
| 314 |   instantiate_dist(urng, "binomial_distribution", | 
|---|
| 315 |                    boost::binomial_distribution<>(4, 0.2)); | 
|---|
| 316 |   instantiate_dist(urng, "geometric_distribution", | 
|---|
| 317 |                    boost::geometric_distribution<>(0.8)); | 
|---|
| 318 |   instantiate_dist(urng, "poisson_distribution", | 
|---|
| 319 |                    boost::poisson_distribution<>(1)); | 
|---|
| 320 |  | 
|---|
| 321 |   instantiate_real_dist(urng, 1.0f); | 
|---|
| 322 |   instantiate_real_dist(urng, 1.0); | 
|---|
| 323 |   instantiate_real_dist(urng, 1.0l); | 
|---|
| 324 |  | 
|---|
| 325 | #if 0 | 
|---|
| 326 |   // We cannot compare the outcomes before/after save with std::abs(x-y) | 
|---|
| 327 |   instantiate_dist("uniform_on_sphere", | 
|---|
| 328 |                    boost::uniform_on_sphere<URNG>(urng, 2)); | 
|---|
| 329 | #endif | 
|---|
| 330 | } | 
|---|
| 331 |  | 
|---|
| 332 | void instantiate_all() | 
|---|
| 333 | { | 
|---|
| 334 |   using namespace boost; | 
|---|
| 335 |  | 
|---|
| 336 | #if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) | 
|---|
| 337 |   instantiate_urng("rand48", rand48(), 0); | 
|---|
| 338 |   rand48 rnd(boost::int32_t(5)); | 
|---|
| 339 |   rand48 rnd2(boost::uint64_t(0x80000000) * 42); | 
|---|
| 340 |   rnd.seed(boost::int32_t(17)); | 
|---|
| 341 |   rnd2.seed(boost::uint64_t(0x80000000) * 49); | 
|---|
| 342 | #endif | 
|---|
| 343 |  | 
|---|
| 344 |   instantiate_urng("minstd_rand0", minstd_rand0(), 0); | 
|---|
| 345 |   instantiate_urng("minstd_rand", minstd_rand(), 0); | 
|---|
| 346 |   minstd_rand mstd(42); | 
|---|
| 347 |   mstd.seed(17); | 
|---|
| 348 |  | 
|---|
| 349 |   instantiate_urng("ecuyer1988", ecuyer1988(), 0); | 
|---|
| 350 |   instantiate_urng("kreutzer1986", kreutzer1986(), 0); | 
|---|
| 351 |   instantiate_urng("hellekalek1995", hellekalek1995(), 0); | 
|---|
| 352 |  | 
|---|
| 353 |   instantiate_urng("mt11213b", mt11213b(), 0u); | 
|---|
| 354 |   instantiate_urng("mt19937", mt19937(), 0u); | 
|---|
| 355 |  | 
|---|
| 356 |   mt19937 mt(boost::uint32_t(17));  // needs to be an exact type match for MSVC | 
|---|
| 357 |   int i = 42; | 
|---|
| 358 |   mt.seed(boost::uint32_t(i)); | 
|---|
| 359 |   mt19937 mt2(mstd); | 
|---|
| 360 |   mt2.seed(mstd); | 
|---|
| 361 |  | 
|---|
| 362 |  | 
|---|
| 363 |   random_number_generator<mt19937> std_rng(mt2); | 
|---|
| 364 |   (void) std_rng(10); | 
|---|
| 365 |  | 
|---|
| 366 |   instantiate_urng("lagged_fibonacci", | 
|---|
| 367 |                    boost::random::lagged_fibonacci<boost::uint32_t, 24, 607, 273>(), | 
|---|
| 368 |                    0u); | 
|---|
| 369 |   instantiate_urng("lagged_fibonacci607", lagged_fibonacci607(), 0.0); | 
|---|
| 370 |  | 
|---|
| 371 |   instantiate_urng("ranlux3", ranlux3(), 0u); | 
|---|
| 372 |   instantiate_urng("ranlux4", ranlux4(), 0u); | 
|---|
| 373 |  | 
|---|
| 374 |   instantiate_urng("ranlux3_01", ranlux3_01(), 0.0f); | 
|---|
| 375 |   instantiate_urng("ranlux4_01", ranlux4_01(), 0.0f); | 
|---|
| 376 |  | 
|---|
| 377 |   instantiate_urng("ranlux64_3_01", ranlux64_3_01(), 0.0); | 
|---|
| 378 |   instantiate_urng("ranlux64_4_01", ranlux64_4_01(), 0.0); | 
|---|
| 379 |  | 
|---|
| 380 |   instantiate_urng("taus88", taus88(), 0u); | 
|---|
| 381 | } | 
|---|
| 382 |  | 
|---|
| 383 | /* | 
|---|
| 384 |  * A few equidistribution tests | 
|---|
| 385 |  */ | 
|---|
| 386 |  | 
|---|
| 387 | // yet to come... | 
|---|
| 388 |  | 
|---|
| 389 | template<class Generator> | 
|---|
| 390 | void check_uniform_int(Generator & gen, int iter) | 
|---|
| 391 | { | 
|---|
| 392 |   std::cout << "testing uniform_int(" << (gen.min)() << "," << (gen.max)()  | 
|---|
| 393 |             << ")" << std::endl; | 
|---|
| 394 |   int range = (gen.max)()-(gen.min)()+1; | 
|---|
| 395 |   std::vector<int> bucket(range); | 
|---|
| 396 |   for(int j = 0; j < iter; j++) { | 
|---|
| 397 |     int result = gen(); | 
|---|
| 398 |     if(result < (gen.min)() || result > (gen.max)()) | 
|---|
| 399 |       std::cerr << "   ... delivers " << result << std::endl; | 
|---|
| 400 |     else | 
|---|
| 401 |       bucket[result-(gen.min)()]++; | 
|---|
| 402 |   } | 
|---|
| 403 |   int sum = 0; | 
|---|
| 404 |   // use a different variable name "k", because MSVC has broken "for" scoping | 
|---|
| 405 |   for(int k = 0; k < range; k++) | 
|---|
| 406 |     sum += bucket[k]; | 
|---|
| 407 |   double avg = static_cast<double>(sum)/range; | 
|---|
| 408 |   double threshold = 2*avg/std::sqrt(static_cast<double>(iter)); | 
|---|
| 409 |   for(int i = 0; i < range; i++) { | 
|---|
| 410 |     if(std::fabs(bucket[i] - avg) > threshold) { | 
|---|
| 411 |       // 95% confidence interval | 
|---|
| 412 |       std::cout << "   ... has bucket[" << i << "] = " << bucket[i]  | 
|---|
| 413 |                 << "  (distance " << (bucket[i] - avg) << ")"  | 
|---|
| 414 |                 << std::endl; | 
|---|
| 415 |     } | 
|---|
| 416 |   } | 
|---|
| 417 | } | 
|---|
| 418 |  | 
|---|
| 419 | template<class Generator> | 
|---|
| 420 | void test_uniform_int(Generator & gen) | 
|---|
| 421 | { | 
|---|
| 422 |   typedef boost::uniform_int<int> int_gen; | 
|---|
| 423 |  | 
|---|
| 424 |   // large range => small range (modulo case) | 
|---|
| 425 |   typedef boost::variate_generator<Generator&, int_gen> level_one; | 
|---|
| 426 |  | 
|---|
| 427 |   level_one uint12(gen, int_gen(1,2)); | 
|---|
| 428 |   BOOST_CHECK((uint12.distribution().min)() == 1); | 
|---|
| 429 |   BOOST_CHECK((uint12.distribution().max)() == 2); | 
|---|
| 430 |   check_uniform_int(uint12, 100000); | 
|---|
| 431 |   level_one uint16(gen, int_gen(1,6)); | 
|---|
| 432 |   check_uniform_int(uint16, 100000); | 
|---|
| 433 |  | 
|---|
| 434 |   // test chaining to get all cases in operator() | 
|---|
| 435 |  | 
|---|
| 436 |   // identity map | 
|---|
| 437 |   typedef boost::variate_generator<level_one&, int_gen> level_two; | 
|---|
| 438 |   level_two uint01(uint12, int_gen(0, 1)); | 
|---|
| 439 |   check_uniform_int(uint01, 100000); | 
|---|
| 440 |  | 
|---|
| 441 |   // small range => larger range | 
|---|
| 442 |   level_two uint05(uint12, int_gen(-3, 2)); | 
|---|
| 443 |   check_uniform_int(uint05, 100000); | 
|---|
| 444 |  | 
|---|
| 445 |   // larger => small range, rejection case | 
|---|
| 446 |   typedef boost::variate_generator<level_two&, int_gen> level_three; | 
|---|
| 447 |   level_three uint1_4(uint05, int_gen(1, 4)); | 
|---|
| 448 |   check_uniform_int(uint1_4, 100000); | 
|---|
| 449 | } | 
|---|
| 450 |  | 
|---|
| 451 | #if defined(BOOST_MSVC) && _MSC_VER < 1300 | 
|---|
| 452 |  | 
|---|
| 453 | // These explicit instantiations are necessary, otherwise MSVC does | 
|---|
| 454 | // not find the <boost/operators.hpp> inline friends. | 
|---|
| 455 | // We ease the typing with a suitable preprocessor macro. | 
|---|
| 456 | #define INSTANT(x) \ | 
|---|
| 457 | template class boost::uniform_smallint<x>; \ | 
|---|
| 458 | template class boost::uniform_int<x>; \ | 
|---|
| 459 | template class boost::uniform_real<x>; \ | 
|---|
| 460 | template class boost::bernoulli_distribution<x>; \ | 
|---|
| 461 | template class boost::geometric_distribution<x>; \ | 
|---|
| 462 | template class boost::triangle_distribution<x>; \ | 
|---|
| 463 | template class boost::exponential_distribution<x>; \ | 
|---|
| 464 | template class boost::normal_distribution<x>; \ | 
|---|
| 465 | template class boost::uniform_on_sphere<x>; \ | 
|---|
| 466 | template class boost::lognormal_distribution<x>; | 
|---|
| 467 |  | 
|---|
| 468 | INSTANT(boost::minstd_rand0) | 
|---|
| 469 | INSTANT(boost::minstd_rand) | 
|---|
| 470 | INSTANT(boost::ecuyer1988) | 
|---|
| 471 | INSTANT(boost::kreutzer1986) | 
|---|
| 472 | INSTANT(boost::hellekalek1995) | 
|---|
| 473 | INSTANT(boost::mt19937) | 
|---|
| 474 | INSTANT(boost::mt11213b) | 
|---|
| 475 |  | 
|---|
| 476 | #undef INSTANT | 
|---|
| 477 | #endif | 
|---|
| 478 |  | 
|---|
| 479 | #if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) | 
|---|
| 480 | // testcase by Mario R�tti | 
|---|
| 481 | class ruetti_gen | 
|---|
| 482 | { | 
|---|
| 483 | public: | 
|---|
| 484 |   typedef boost::uint64_t result_type; | 
|---|
| 485 |   result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 0; } | 
|---|
| 486 |   result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return std::numeric_limits<result_type>::max BOOST_PREVENT_MACRO_SUBSTITUTION (); } | 
|---|
| 487 |   result_type operator()() { return (max)()-1; } | 
|---|
| 488 | }; | 
|---|
| 489 |  | 
|---|
| 490 | void test_overflow_range() | 
|---|
| 491 | { | 
|---|
| 492 |   ruetti_gen gen; | 
|---|
| 493 |   boost::variate_generator<ruetti_gen, boost::uniform_int<> > | 
|---|
| 494 |     rng(gen, boost::uniform_int<>(0, 10)); | 
|---|
| 495 |   for (int i=0;i<10;i++) | 
|---|
| 496 |     (void) rng(); | 
|---|
| 497 | } | 
|---|
| 498 | #else | 
|---|
| 499 | void test_overflow_range() | 
|---|
| 500 | { } | 
|---|
| 501 | #endif | 
|---|
| 502 |  | 
|---|
| 503 | int test_main(int, char*[]) | 
|---|
| 504 | { | 
|---|
| 505 |  | 
|---|
| 506 | #if !defined(__INTEL_COMPILER) || !defined(_MSC_VER) || __INTEL_COMPILER > 700  | 
|---|
| 507 |   instantiate_all(); | 
|---|
| 508 |   validate_all(); | 
|---|
| 509 |   boost::mt19937 mt; | 
|---|
| 510 |   test_uniform_int(mt); | 
|---|
| 511 |  | 
|---|
| 512 |   // bug report from Ken Mahler:  This used to lead to an endless loop. | 
|---|
| 513 |   typedef boost::uniform_int<unsigned int> uint_dist; | 
|---|
| 514 |   boost::minstd_rand mr; | 
|---|
| 515 |   boost::variate_generator<boost::minstd_rand, uint_dist> r2(mr, | 
|---|
| 516 |                                                             uint_dist(0, 0xffffffff)); | 
|---|
| 517 |   r2(); | 
|---|
| 518 |   r2(); | 
|---|
| 519 |  | 
|---|
| 520 |   // bug report from Fernando Cacciola:  This used to lead to an endless loop. | 
|---|
| 521 |   // also from Douglas Gregor | 
|---|
| 522 |   boost::variate_generator<boost::minstd_rand, boost::uniform_int<> > x(mr, boost::uniform_int<>(0, 8361)); | 
|---|
| 523 |   (void) x(); | 
|---|
| 524 |  | 
|---|
| 525 |   // bug report from Alan Stokes and others: this throws an assertion | 
|---|
| 526 |   boost::variate_generator<boost::minstd_rand, boost::uniform_int<> > y(mr, boost::uniform_int<>(1,1)); | 
|---|
| 527 |   std::cout << "uniform_int(1,1) " << y() << ", " << y() << ", " << y() | 
|---|
| 528 |             << std::endl; | 
|---|
| 529 |  | 
|---|
| 530 |   test_overflow_range(); | 
|---|
| 531 |  | 
|---|
| 532 |   return 0; | 
|---|
| 533 | #else | 
|---|
| 534 |   std::cout << "Intel 7.00 on Win32 loops, so the test is disabled\n"; | 
|---|
| 535 |   return 1; | 
|---|
| 536 | #endif | 
|---|
| 537 | } | 
|---|