1/* boost test_uniform_int.ipp 2 * 3 * Copyright Jens Maurer 2000 4 * Copyright Steven Watanabe 2011 5 * Distributed under the Boost Software License, Version 1.0. (See 6 * accompanying file LICENSE_1_0.txt or copy at 7 * http://www.boost.org/LICENSE_1_0.txt) 8 * 9 * $Id$ 10 */ 11 12#include <numeric> 13#include <sstream> 14#include <vector> 15#include <boost/config.hpp> 16#include <boost/cstdint.hpp> 17#include <boost/limits.hpp> 18#include <boost/random/mersenne_twister.hpp> 19#include <boost/random/linear_congruential.hpp> 20#include <boost/random/lagged_fibonacci.hpp> 21#include <boost/random/variate_generator.hpp> 22#include "chi_squared_test.hpp" 23 24#define BOOST_TEST_MAIN 25#include <boost/test/unit_test.hpp> 26 27template<class Generator> 28void check_uniform_int(Generator & gen, int iter) 29{ 30 int range = (gen.max)()-(gen.min)()+1; 31 std::vector<int> bucket(range); 32 for(int j = 0; j < iter; j++) { 33 int result = gen(); 34 BOOST_CHECK_GE(result, (gen.min)()); 35 BOOST_CHECK_LE(result, (gen.max)()); 36 if(result >= (gen.min)() && result <= (gen.max)()) { 37 bucket[result-(gen.min)()]++; 38 } 39 } 40 int sum = std::accumulate(bucket.begin(), bucket.end(), 0); 41 std::vector<double> expected(range, 1.0 / range); 42 BOOST_CHECK_LT(chi_squared_test(bucket, expected, sum), 0.99); 43} 44 45BOOST_AUTO_TEST_CASE(test_uniform_int) 46{ 47 boost::random::mt19937 gen; 48 typedef BOOST_RANDOM_UNIFORM_INT<int> int_gen; 49 50 // large range => small range (modulo case) 51 typedef boost::random::variate_generator<boost::random::mt19937&, int_gen> level_one; 52 53 level_one uint12(gen, int_gen(1,2)); 54 BOOST_CHECK((uint12.distribution().min)() == 1); 55 BOOST_CHECK((uint12.distribution().max)() == 2); 56 check_uniform_int(uint12, 100000); 57 level_one uint16(gen, int_gen(1,6)); 58 check_uniform_int(uint16, 100000); 59 60 // test chaining to get all cases in operator() 61 62 // identity map 63 typedef boost::random::variate_generator<level_one&, int_gen> level_two; 64 level_two uint01(uint12, int_gen(0, 1)); 65 check_uniform_int(uint01, 100000); 66 67 // small range => larger range 68 level_two uint05(uint12, int_gen(-3, 2)); 69 check_uniform_int(uint05, 100000); 70 71 // small range => larger range 72 level_two uint099(uint12, int_gen(0, 99)); 73 check_uniform_int(uint099, 100000); 74 75 // larger => small range, rejection case 76 typedef boost::random::variate_generator<level_two&, int_gen> level_three; 77 level_three uint1_4(uint05, int_gen(1, 4)); 78 check_uniform_int(uint1_4, 100000); 79 80 typedef BOOST_RANDOM_UNIFORM_INT<boost::uint8_t> int8_gen; 81 typedef boost::random::variate_generator<boost::random::mt19937&, int8_gen> gen8_t; 82 83 gen8_t gen8_03(gen, int8_gen(0, 3)); 84 85 // use the full range of the type, where the destination 86 // range is a power of the source range 87 typedef boost::random::variate_generator<gen8_t, int8_gen> uniform_uint8; 88 uniform_uint8 uint8_0255(gen8_03, int8_gen(0, 255)); 89 check_uniform_int(uint8_0255, 100000); 90 91 // use the full range, but a generator whose range is not 92 // a root of the destination range. 93 gen8_t gen8_02(gen, int8_gen(0, 2)); 94 uniform_uint8 uint8_0255_2(gen8_02, int8_gen(0, 255)); 95 check_uniform_int(uint8_0255_2, 100000); 96 97 // expand the range to a larger type. 98 typedef boost::random::variate_generator<gen8_t, int_gen> uniform_uint_from8; 99 uniform_uint_from8 uint0300(gen8_03, int_gen(0, 300)); 100 check_uniform_int(uint0300, 100000); 101} 102 103#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) 104 105// testcase by Mario Rutti 106class ruetti_gen 107{ 108public: 109 ruetti_gen() : state((max)() - 1) {} 110 typedef boost::uint64_t result_type; 111 result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 0; } 112 result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return std::numeric_limits<result_type>::max BOOST_PREVENT_MACRO_SUBSTITUTION (); } 113 result_type operator()() { return state--; } 114private: 115 result_type state; 116}; 117 118BOOST_AUTO_TEST_CASE(test_overflow_range) 119{ 120 ruetti_gen gen; 121 BOOST_RANDOM_DISTRIBUTION dist(0, 10); 122 for (int i=0;i<10;i++) { 123 dist(gen); 124 } 125} 126 127#endif 128 129BOOST_AUTO_TEST_CASE(test_misc) 130{ 131 // bug report from Ken Mahler: This used to lead to an endless loop. 132 typedef BOOST_RANDOM_UNIFORM_INT<unsigned int> uint_dist; 133 boost::minstd_rand mr; 134 boost::variate_generator<boost::minstd_rand, uint_dist> r2(mr, 135 uint_dist(0, 0xffffffff)); 136 r2(); 137 r2(); 138 139 // bug report from Fernando Cacciola: This used to lead to an endless loop. 140 // also from Douglas Gregor 141 boost::variate_generator<boost::minstd_rand, BOOST_RANDOM_DISTRIBUTION > x(mr, BOOST_RANDOM_DISTRIBUTION(0, 8361)); 142 x(); 143 144 // bug report from Alan Stokes and others: this throws an assertion 145 boost::variate_generator<boost::minstd_rand, BOOST_RANDOM_DISTRIBUTION > y(mr, BOOST_RANDOM_DISTRIBUTION(1,1)); 146 y(); 147 y(); 148 y(); 149} 150