test_uniform_int.ipp 4.9 KB

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