/* boost random_test.cpp various tests * * Copyright Jens Maurer 2000 * 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) * * $Id$ */ #if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 #pragma warning( disable : 4786 ) #endif #include #include #include #include #include #include #include #include #include #include #ifdef BOOST_NO_STDC_NAMESPACE namespace std { using ::abs; using ::fabs; using ::pow; } #endif /* * General portability note: * MSVC mis-compiles explicit function template instantiations. * For example, f() and f() are both compiled to call f(). * BCC is unable to implicitly convert a "const char *" to a std::string * when using explicit function template instantiations. * * Therefore, avoid explicit function template instantiations. */ /* * A few equidistribution tests */ // yet to come... template void check_uniform_int(Generator & gen, int iter) { std::cout << "testing uniform_int(" << (gen.min)() << "," << (gen.max)() << ")" << std::endl; int range = (gen.max)()-(gen.min)()+1; std::vector bucket(range); for(int j = 0; j < iter; j++) { int result = gen(); if(result < (gen.min)() || result > (gen.max)()) std::cerr << " ... delivers " << result << std::endl; else bucket[result-(gen.min)()]++; } int sum = 0; // use a different variable name "k", because MSVC has broken "for" scoping for(int k = 0; k < range; k++) sum += bucket[k]; double avg = static_cast(sum)/range; double p = 1 / static_cast(range); double threshold = 2*std::sqrt(static_cast(iter)*p*(1-p)); for(int i = 0; i < range; i++) { if(std::fabs(bucket[i] - avg) > threshold) { // 95% confidence interval std::cout << " ... has bucket[" << i << "] = " << bucket[i] << " (distance " << (bucket[i] - avg) << ")" << std::endl; } } } template void test_uniform_int(Generator & gen) { typedef boost::uniform_int int_gen; // large range => small range (modulo case) typedef boost::variate_generator level_one; level_one uint12(gen, int_gen(1,2)); BOOST_CHECK((uint12.distribution().min)() == 1); BOOST_CHECK((uint12.distribution().max)() == 2); check_uniform_int(uint12, 100000); level_one uint16(gen, int_gen(1,6)); check_uniform_int(uint16, 100000); // test chaining to get all cases in operator() // identity map typedef boost::variate_generator level_two; level_two uint01(uint12, int_gen(0, 1)); check_uniform_int(uint01, 100000); // 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_three; level_three uint1_4(uint05, int_gen(1, 4)); check_uniform_int(uint1_4, 100000); typedef boost::uniform_int int8_gen; typedef boost::variate_generator 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 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 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 // These explicit instantiations are necessary, otherwise MSVC does // not find the inline friends. // We ease the typing with a suitable preprocessor macro. #define INSTANT(x) \ template class boost::uniform_smallint; \ template class boost::uniform_int; \ template class boost::uniform_real; \ template class boost::bernoulli_distribution; \ template class boost::geometric_distribution; \ template class boost::triangle_distribution; \ template class boost::exponential_distribution; \ template class boost::normal_distribution; \ template class boost::uniform_on_sphere; \ template class boost::lognormal_distribution; INSTANT(boost::minstd_rand0) INSTANT(boost::minstd_rand) INSTANT(boost::ecuyer1988) INSTANT(boost::kreutzer1986) INSTANT(boost::hellekalek1995) INSTANT(boost::mt19937) INSTANT(boost::mt11213b) #undef INSTANT #endif #if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) // testcase by Mario Rutti 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::max BOOST_PREVENT_MACRO_SUBSTITUTION (); } result_type operator()() { return state--; } private: result_type state; }; void test_overflow_range() { ruetti_gen gen; boost::variate_generator > rng(gen, boost::uniform_int<>(0, 10)); for (int i=0;i<10;i++) (void) rng(); } #else void test_overflow_range() { } #endif template struct rand_for_random_shuffle { explicit rand_for_random_shuffle(EngineT &engine) : m_engine(engine) { } template IntT operator()(IntT upperBound) { assert(upperBound > 0); if (upperBound == 1) { return 0; } typedef boost::uniform_int distribution_type; typedef boost::variate_generator 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 generator_type; boost::mt19937 engine1(1234); boost::mt19937 engine2(1234); rand_for_random_shuffle referenceRand(engine1); distribution_type dist(0,10); generator_type testRand(engine2, dist); std::vector referenceVec; for (int i = 0; i < 200; ++i) { referenceVec.push_back(i); } std::vector testVec(referenceVec); std::random_shuffle(referenceVec.begin(), referenceVec.end(), referenceRand); std::random_shuffle(testVec.begin(), testVec.end(), testRand); typedef std::vector::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*[]) { #if !defined(__INTEL_COMPILER) || !defined(_MSC_VER) || __INTEL_COMPILER > 700 boost::mt19937 mt; test_uniform_int(mt); // bug report from Ken Mahler: This used to lead to an endless loop. typedef boost::uniform_int uint_dist; boost::minstd_rand mr; boost::variate_generator r2(mr, uint_dist(0, 0xffffffff)); r2(); r2(); // bug report from Fernando Cacciola: This used to lead to an endless loop. // also from Douglas Gregor boost::variate_generator > x(mr, boost::uniform_int<>(0, 8361)); (void) x(); // bug report from Alan Stokes and others: this throws an assertion boost::variate_generator > y(mr, boost::uniform_int<>(1,1)); std::cout << "uniform_int(1,1) " << y() << ", " << y() << ", " << y() << std::endl; test_overflow_range(); test_random_shuffle(); return 0; #else std::cout << "Intel 7.00 on Win32 loops, so the test is disabled\n"; return 1; #endif }