diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 4de9017..cf60e6c 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -10,7 +10,6 @@ import testing ; project /boost/random/test ; -run random_test.cpp ; run test_const_mod.cpp /boost//unit_test_framework ; run test_generate_canonical.cpp /boost//unit_test_framework ; run test_random_number_generator.cpp /boost//unit_test_framework ; diff --git a/test/random_test.cpp b/test/random_test.cpp deleted file mode 100644 index b6a8887..0000000 --- a/test/random_test.cpp +++ /dev/null @@ -1,291 +0,0 @@ -/* 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 -} diff --git a/test/test_old_uniform_int_distribution.cpp b/test/test_old_uniform_int_distribution.cpp index b05c0c6..f033ad0 100644 --- a/test/test_old_uniform_int_distribution.cpp +++ b/test/test_old_uniform_int_distribution.cpp @@ -36,3 +36,41 @@ #define BOOST_RANDOM_TEST2_MAX 19 #include "test_distribution.ipp" + +#define BOOST_RANDOM_UNIFORM_INT boost::uniform_int + +#include "test_uniform_int.ipp" + +#include +#include + +// Test that uniform_int<> can be used with std::random_shuffle +// Author: Jos Hickson +BOOST_AUTO_TEST_CASE(test_random_shuffle) +{ + typedef boost::uniform_int<> distribution_type; + typedef boost::variate_generator generator_type; + + boost::mt19937 engine1(1234); + boost::mt19937 engine2(1234); + + boost::random::random_number_generator 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); + + BOOST_CHECK_EQUAL_COLLECTIONS( + testVec.begin(), testVec.end(), + referenceVec.begin(), referenceVec.end()); +} diff --git a/test/test_uniform_int.ipp b/test/test_uniform_int.ipp new file mode 100644 index 0000000..fe35c39 --- /dev/null +++ b/test/test_uniform_int.ipp @@ -0,0 +1,149 @@ +/* boost test_uniform_int.ipp + * + * Copyright Jens Maurer 2000 + * Copyright Steven Watanabe 2011 + * 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$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "chi_squared_test.hpp" + +#define BOOST_TEST_MAIN +#include + +template +void check_uniform_int(Generator & gen, int iter) +{ + int range = (gen.max)()-(gen.min)()+1; + std::vector bucket(range); + for(int j = 0; j < iter; j++) { + int result = gen(); + BOOST_CHECK_GE(result, (gen.min)()); + BOOST_CHECK_LE(result, (gen.max)()); + if(result >= (gen.min)() && result <= (gen.max)()) { + bucket[result-(gen.min)()]++; + } + } + int sum = std::accumulate(bucket.begin(), bucket.end(), 0); + std::vector expected(range, 1.0 / range); + BOOST_CHECK_LT(chi_squared_test(bucket, expected, sum), 0.99); +} + +BOOST_AUTO_TEST_CASE(test_uniform_int) +{ + boost::random::mt19937 gen; + typedef BOOST_RANDOM_UNIFORM_INT int_gen; + + // large range => small range (modulo case) + typedef boost::random::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::random::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::random::variate_generator level_three; + level_three uint1_4(uint05, int_gen(1, 4)); + check_uniform_int(uint1_4, 100000); + + typedef BOOST_RANDOM_UNIFORM_INT int8_gen; + typedef boost::random::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::random::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::random::variate_generator uniform_uint_from8; + uniform_uint_from8 uint0300(gen8_03, int_gen(0, 300)); + check_uniform_int(uint0300, 100000); +} + +#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; +}; + +BOOST_AUTO_TEST_CASE(test_overflow_range) +{ + ruetti_gen gen; + BOOST_RANDOM_DISTRIBUTION dist(0, 10); + for (int i=0;i<10;i++) { + dist(gen); + } +} + +#endif + +BOOST_AUTO_TEST_CASE(test_misc) +{ + // bug report from Ken Mahler: This used to lead to an endless loop. + typedef BOOST_RANDOM_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_RANDOM_DISTRIBUTION(0, 8361)); + x(); + + // bug report from Alan Stokes and others: this throws an assertion + boost::variate_generator y(mr, BOOST_RANDOM_DISTRIBUTION(1,1)); + y(); + y(); + y(); +} diff --git a/test/test_uniform_int_distribution.cpp b/test/test_uniform_int_distribution.cpp index 5f08d7c..5863163 100644 --- a/test/test_uniform_int_distribution.cpp +++ b/test/test_uniform_int_distribution.cpp @@ -36,3 +36,7 @@ #define BOOST_RANDOM_TEST2_MAX 19 #include "test_distribution.ipp" + +#define BOOST_RANDOM_UNIFORM_INT boost::random::uniform_int_distribution + +#include "test_uniform_int.ipp"