summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/random/test/test_uniform_int.ipp
blob: fe35c39a22be9a346f5da446deeb449308442532 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
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 <numeric>
#include <sstream>
#include <vector>
#include <boost/config.hpp>
#include <boost/cstdint.hpp>
#include <boost/limits.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/linear_congruential.hpp>
#include <boost/random/lagged_fibonacci.hpp>
#include <boost/random/variate_generator.hpp>
#include "chi_squared_test.hpp"

#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>

template<class Generator>
void check_uniform_int(Generator & gen, int iter)
{
    int range = (gen.max)()-(gen.min)()+1;
    std::vector<int> 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<double> 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> int_gen;

    // large range => small range (modulo case)
    typedef boost::random::variate_generator<boost::random::mt19937&, int_gen> 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_one&, int_gen> 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_two&, int_gen> level_three;
    level_three uint1_4(uint05, int_gen(1, 4));
    check_uniform_int(uint1_4, 100000);

    typedef BOOST_RANDOM_UNIFORM_INT<boost::uint8_t> int8_gen;
    typedef boost::random::variate_generator<boost::random::mt19937&, int8_gen> 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<gen8_t, int8_gen> 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<gen8_t, int_gen> 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<result_type>::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<unsigned int> uint_dist;
    boost::minstd_rand mr;
    boost::variate_generator<boost::minstd_rand, uint_dist> 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<boost::minstd_rand, BOOST_RANDOM_DISTRIBUTION > x(mr, BOOST_RANDOM_DISTRIBUTION(0, 8361));
    x();

    // bug report from Alan Stokes and others: this throws an assertion
    boost::variate_generator<boost::minstd_rand, BOOST_RANDOM_DISTRIBUTION > y(mr, BOOST_RANDOM_DISTRIBUTION(1,1));
    y();
    y();
    y();
}