• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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