Ticket #1546: bug_1546.diff
File bug_1546.diff, 7.9 KB (added by , 15 years ago) |
---|
-
boost/random/uniform_int.hpp
59 59 template<class Engine> 60 60 result_type operator()(Engine& eng) 61 61 { 62 return generate(eng, _min, _max, _range); 63 } 64 65 template<class Engine> 66 result_type operator()(Engine& eng, result_type n) 67 { 68 assert(n > 0); 69 70 if (n == 1) 71 { 72 return 0; 73 } 74 75 return generate(eng, 0, n - 1, n - 1); 76 } 77 78 #if !defined(BOOST_NO_OPERATORS_IN_NAMESPACE) && !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) 79 template<class CharT, class Traits> 80 friend std::basic_ostream<CharT,Traits>& 81 operator<<(std::basic_ostream<CharT,Traits>& os, const uniform_int& ud) 82 { 83 os << ud._min << " " << ud._max; 84 return os; 85 } 86 87 template<class CharT, class Traits> 88 friend std::basic_istream<CharT,Traits>& 89 operator>>(std::basic_istream<CharT,Traits>& is, uniform_int& ud) 90 { 91 # if BOOST_WORKAROUND(_MSC_FULL_VER, BOOST_TESTED_AT(13102292)) && BOOST_MSVC == 1400 92 return detail::extract_uniform_int(is, ud, ud.impl); 93 # else 94 is >> std::ws >> ud._min >> std::ws >> ud._max; 95 ud.init(); 96 return is; 97 # endif 98 } 99 #endif 100 101 private: 102 template<class Engine> 103 static result_type generate(Engine& eng, result_type min_value, result_type max_value, range_type range) 104 { 62 105 typedef typename Engine::result_type base_result; 63 106 // ranges are always unsigned 64 107 typedef typename random::detail::make_unsigned<base_result>::type base_unsigned; … … 66 109 const base_unsigned brange = 67 110 random::detail::subtract<base_result>()((eng.max)(), (eng.min)()); 68 111 69 if( _range == 0) {70 return _min;71 } else if(brange == _range) {112 if(range == 0) { 113 return min_value; 114 } else if(brange == range) { 72 115 // this will probably never happen in real life 73 116 // basically nothing to do; just take care we don't overflow / underflow 74 117 base_unsigned v = random::detail::subtract<base_result>()(eng(), bmin); 75 return random::detail::add<base_unsigned, result_type>()(v, _min);76 } else if(brange < _range) {118 return random::detail::add<base_unsigned, result_type>()(v, min_value); 119 } else if(brange < range) { 77 120 // use rejection method to handle things like 0..3 --> 0..4 78 121 for(;;) { 79 122 // concatenate several invocations of the base RNG 80 123 // take extra care to avoid overflows 81 124 range_type limit; 82 if( _range == (std::numeric_limits<range_type>::max)()) {83 limit = _range/(range_type(brange)+1);84 if( _range % range_type(brange)+1 == range_type(brange))125 if(range == (std::numeric_limits<range_type>::max)()) { 126 limit = range/(range_type(brange)+1); 127 if(range % range_type(brange)+1 == range_type(brange)) 85 128 ++limit; 86 129 } else { 87 limit = ( _range+1)/(range_type(brange)+1);130 limit = (range+1)/(range_type(brange)+1); 88 131 } 89 132 // We consider "result" as expressed to base (brange+1): 90 133 // For every power of (brange+1), we determine a random factor … … 95 138 mult *= range_type(brange)+range_type(1); 96 139 } 97 140 if(mult == limit) 98 // _range+1 is an integer power of brange+1: no rejections required141 // range+1 is an integer power of brange+1: no rejections required 99 142 return result; 100 // _range/mult < brange+1 -> no endless loop101 result += uniform_int<range_type>(0, _range/mult)(eng) * mult;102 if(result <= _range)103 return random::detail::add<range_type, result_type>()(result, _min);143 // range/mult < brange+1 -> no endless loop 144 result += uniform_int<range_type>(0, range/mult)(eng) * mult; 145 if(result <= range) 146 return random::detail::add<range_type, result_type>()(result, min_value); 104 147 } 105 148 } else { // brange > range 106 if(brange / _range > 4 /* quantization_cutoff */ ) {149 if(brange / range > 4 /* quantization_cutoff */ ) { 107 150 // the new range is vastly smaller than the source range, 108 151 // so quantization effects are not relevant 109 return boost::uniform_smallint<result_type>( _min, _max)(eng);152 return boost::uniform_smallint<result_type>(min_value, max_value)(eng); 110 153 } else { 111 154 // use rejection method to handle cases like 0..5 -> 0..4 112 155 for(;;) { … … 114 157 random::detail::subtract<base_result>()(eng(), bmin); 115 158 // result and range are non-negative, and result is possibly larger 116 159 // than range, so the cast is safe 117 if(result <= static_cast<base_unsigned>( _range))118 return random::detail::add<base_unsigned, result_type>()(result, _min);160 if(result <= static_cast<base_unsigned>(range)) 161 return random::detail::add<base_unsigned, result_type>()(result, min_value); 119 162 } 120 163 } 121 164 } 122 165 } 123 166 124 #if !defined(BOOST_NO_OPERATORS_IN_NAMESPACE) && !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)125 template<class CharT, class Traits>126 friend std::basic_ostream<CharT,Traits>&127 operator<<(std::basic_ostream<CharT,Traits>& os, const uniform_int& ud)128 {129 os << ud._min << " " << ud._max;130 return os;131 }132 133 template<class CharT, class Traits>134 friend std::basic_istream<CharT,Traits>&135 operator>>(std::basic_istream<CharT,Traits>& is, uniform_int& ud)136 {137 # if BOOST_WORKAROUND(_MSC_FULL_VER, BOOST_TESTED_AT(13102292)) && BOOST_MSVC == 1400138 return detail::extract_uniform_int(is, ud, ud.impl);139 # else140 is >> std::ws >> ud._min >> std::ws >> ud._max;141 ud.init();142 return is;143 # endif144 }145 #endif146 147 private:148 167 void init() 149 168 { 150 169 _range = random::detail::subtract<result_type>()(_max, _min); -
libs/random/random_test.cpp
500 500 { } 501 501 #endif 502 502 503 template <typename EngineT> 504 struct rand_for_random_shuffle 505 { 506 explicit rand_for_random_shuffle(EngineT &engine) 507 : m_engine(engine) 508 { } 509 510 template <typename IntT> 511 IntT operator()(IntT upperBound) 512 { 513 assert(upperBound > 0); 514 515 if (upperBound == 1) 516 { 517 return 0; 518 } 519 520 typedef boost::uniform_int<IntT> distribution_type; 521 typedef boost::variate_generator<EngineT &, distribution_type> generator_type; 522 523 return generator_type(m_engine, distribution_type(0, upperBound - 1))(); 524 } 525 526 EngineT &m_engine; 527 528 }; 529 530 // Test that uniform_int<> can be used with std::random_shuffle 531 // Author: Jos Hickson 532 void test_random_shuffle() 533 { 534 typedef boost::uniform_int<> distribution_type; 535 typedef boost::variate_generator<boost::mt19937 &, distribution_type> generator_type; 536 537 boost::mt19937 engine1(1234); 538 boost::mt19937 engine2(1234); 539 540 rand_for_random_shuffle<boost::mt19937> referenceRand(engine1); 541 542 distribution_type dist(0,10); 543 generator_type testRand(engine2, dist); 544 545 std::vector<int> referenceVec; 546 547 for (int i = 0; i < 200; ++i) 548 { 549 referenceVec.push_back(i); 550 } 551 552 std::vector<int> testVec(referenceVec); 553 554 std::random_shuffle(referenceVec.begin(), referenceVec.end(), referenceRand); 555 std::random_shuffle(testVec.begin(), testVec.end(), testRand); 556 557 typedef std::vector<int>::iterator iter_type; 558 iter_type theEnd(referenceVec.end()); 559 560 for (iter_type referenceIter(referenceVec.begin()), testIter(testVec.begin()); 561 referenceIter != theEnd; 562 ++referenceIter, ++testIter) 563 { 564 BOOST_CHECK_EQUAL(*referenceIter, *testIter); 565 } 566 } 567 568 503 569 int test_main(int, char*[]) 504 570 { 505 571 … … 528 594 << std::endl; 529 595 530 596 test_overflow_range(); 597 test_random_shuffle(); 531 598 532 599 return 0; 533 600 #else