|
libstdc++
|
00001 // Class template uniform_int_distribution -*- C++ -*- 00002 00003 // Copyright (C) 2009-2016 Free Software Foundation, Inc. 00004 // 00005 // This file is part of the GNU ISO C++ Library. This library is free 00006 // software; you can redistribute it and/or modify it under the 00007 // terms of the GNU General Public License as published by the 00008 // Free Software Foundation; either version 3, or (at your option) 00009 // any later version. 00010 00011 // This library is distributed in the hope that it will be useful, 00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 // GNU General Public License for more details. 00015 00016 // Under Section 7 of GPL version 3, you are granted additional 00017 // permissions described in the GCC Runtime Library Exception, version 00018 // 3.1, as published by the Free Software Foundation. 00019 00020 // You should have received a copy of the GNU General Public License and 00021 // a copy of the GCC Runtime Library Exception along with this program; 00022 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 00023 // <http://www.gnu.org/licenses/>. 00024 00025 /** 00026 * @file bits/uniform_int_dist.h 00027 * This is an internal header file, included by other library headers. 00028 * Do not attempt to use it directly. @headername{random} 00029 */ 00030 00031 #ifndef _GLIBCXX_BITS_UNIFORM_INT_DIST_H 00032 #define _GLIBCXX_BITS_UNIFORM_INT_DIST_H 00033 00034 #include <type_traits> 00035 #include <limits> 00036 00037 namespace std _GLIBCXX_VISIBILITY(default) 00038 { 00039 00040 namespace __detail 00041 { 00042 _GLIBCXX_BEGIN_NAMESPACE_VERSION 00043 /* Determine whether number is a power of 2. */ 00044 template<typename _Tp> 00045 inline bool 00046 _Power_of_2(_Tp __x) 00047 { 00048 return ((__x - 1) & __x) == 0; 00049 }; 00050 _GLIBCXX_END_NAMESPACE_VERSION 00051 } 00052 00053 _GLIBCXX_BEGIN_NAMESPACE_VERSION 00054 00055 /** 00056 * @brief Uniform discrete distribution for random numbers. 00057 * 00058 * A discrete random distribution on the range @f$[min, max]@f$ with equal 00059 * probability throughout the range. 00060 * 00061 * @ingroup random_distributions_uniform 00062 */ 00063 template<typename _IntType = int> 00064 class uniform_int_distribution 00065 { 00066 static_assert(std::is_integral<_IntType>::value, 00067 "template argument not an integral type"); 00068 00069 public: 00070 /** The type of the range of the distribution. */ 00071 typedef _IntType result_type; 00072 /** Parameter type. */ 00073 struct param_type 00074 { 00075 typedef uniform_int_distribution<_IntType> distribution_type; 00076 00077 explicit 00078 param_type(_IntType __a = 0, 00079 _IntType __b = std::numeric_limits<_IntType>::max()) 00080 : _M_a(__a), _M_b(__b) 00081 { 00082 _GLIBCXX_DEBUG_ASSERT(_M_a <= _M_b); 00083 } 00084 00085 result_type 00086 a() const 00087 { return _M_a; } 00088 00089 result_type 00090 b() const 00091 { return _M_b; } 00092 00093 friend bool 00094 operator==(const param_type& __p1, const param_type& __p2) 00095 { return __p1._M_a == __p2._M_a && __p1._M_b == __p2._M_b; } 00096 00097 private: 00098 _IntType _M_a; 00099 _IntType _M_b; 00100 }; 00101 00102 public: 00103 /** 00104 * @brief Constructs a uniform distribution object. 00105 */ 00106 explicit 00107 uniform_int_distribution(_IntType __a = 0, 00108 _IntType __b = std::numeric_limits<_IntType>::max()) 00109 : _M_param(__a, __b) 00110 { } 00111 00112 explicit 00113 uniform_int_distribution(const param_type& __p) 00114 : _M_param(__p) 00115 { } 00116 00117 /** 00118 * @brief Resets the distribution state. 00119 * 00120 * Does nothing for the uniform integer distribution. 00121 */ 00122 void 00123 reset() { } 00124 00125 result_type 00126 a() const 00127 { return _M_param.a(); } 00128 00129 result_type 00130 b() const 00131 { return _M_param.b(); } 00132 00133 /** 00134 * @brief Returns the parameter set of the distribution. 00135 */ 00136 param_type 00137 param() const 00138 { return _M_param; } 00139 00140 /** 00141 * @brief Sets the parameter set of the distribution. 00142 * @param __param The new parameter set of the distribution. 00143 */ 00144 void 00145 param(const param_type& __param) 00146 { _M_param = __param; } 00147 00148 /** 00149 * @brief Returns the inclusive lower bound of the distribution range. 00150 */ 00151 result_type 00152 min() const 00153 { return this->a(); } 00154 00155 /** 00156 * @brief Returns the inclusive upper bound of the distribution range. 00157 */ 00158 result_type 00159 max() const 00160 { return this->b(); } 00161 00162 /** 00163 * @brief Generating functions. 00164 */ 00165 template<typename _UniformRandomNumberGenerator> 00166 result_type 00167 operator()(_UniformRandomNumberGenerator& __urng) 00168 { return this->operator()(__urng, _M_param); } 00169 00170 template<typename _UniformRandomNumberGenerator> 00171 result_type 00172 operator()(_UniformRandomNumberGenerator& __urng, 00173 const param_type& __p); 00174 00175 template<typename _ForwardIterator, 00176 typename _UniformRandomNumberGenerator> 00177 void 00178 __generate(_ForwardIterator __f, _ForwardIterator __t, 00179 _UniformRandomNumberGenerator& __urng) 00180 { this->__generate(__f, __t, __urng, _M_param); } 00181 00182 template<typename _ForwardIterator, 00183 typename _UniformRandomNumberGenerator> 00184 void 00185 __generate(_ForwardIterator __f, _ForwardIterator __t, 00186 _UniformRandomNumberGenerator& __urng, 00187 const param_type& __p) 00188 { this->__generate_impl(__f, __t, __urng, __p); } 00189 00190 template<typename _UniformRandomNumberGenerator> 00191 void 00192 __generate(result_type* __f, result_type* __t, 00193 _UniformRandomNumberGenerator& __urng, 00194 const param_type& __p) 00195 { this->__generate_impl(__f, __t, __urng, __p); } 00196 00197 /** 00198 * @brief Return true if two uniform integer distributions have 00199 * the same parameters. 00200 */ 00201 friend bool 00202 operator==(const uniform_int_distribution& __d1, 00203 const uniform_int_distribution& __d2) 00204 { return __d1._M_param == __d2._M_param; } 00205 00206 private: 00207 template<typename _ForwardIterator, 00208 typename _UniformRandomNumberGenerator> 00209 void 00210 __generate_impl(_ForwardIterator __f, _ForwardIterator __t, 00211 _UniformRandomNumberGenerator& __urng, 00212 const param_type& __p); 00213 00214 param_type _M_param; 00215 }; 00216 00217 template<typename _IntType> 00218 template<typename _UniformRandomNumberGenerator> 00219 typename uniform_int_distribution<_IntType>::result_type 00220 uniform_int_distribution<_IntType>:: 00221 operator()(_UniformRandomNumberGenerator& __urng, 00222 const param_type& __param) 00223 { 00224 typedef typename _UniformRandomNumberGenerator::result_type 00225 _Gresult_type; 00226 typedef typename std::make_unsigned<result_type>::type __utype; 00227 typedef typename std::common_type<_Gresult_type, __utype>::type 00228 __uctype; 00229 00230 const __uctype __urngmin = __urng.min(); 00231 const __uctype __urngmax = __urng.max(); 00232 const __uctype __urngrange = __urngmax - __urngmin; 00233 const __uctype __urange 00234 = __uctype(__param.b()) - __uctype(__param.a()); 00235 00236 __uctype __ret; 00237 00238 if (__urngrange > __urange) 00239 { 00240 // downscaling 00241 const __uctype __uerange = __urange + 1; // __urange can be zero 00242 const __uctype __scaling = __urngrange / __uerange; 00243 const __uctype __past = __uerange * __scaling; 00244 do 00245 __ret = __uctype(__urng()) - __urngmin; 00246 while (__ret >= __past); 00247 __ret /= __scaling; 00248 } 00249 else if (__urngrange < __urange) 00250 { 00251 // upscaling 00252 /* 00253 Note that every value in [0, urange] 00254 can be written uniquely as 00255 00256 (urngrange + 1) * high + low 00257 00258 where 00259 00260 high in [0, urange / (urngrange + 1)] 00261 00262 and 00263 00264 low in [0, urngrange]. 00265 */ 00266 __uctype __tmp; // wraparound control 00267 do 00268 { 00269 const __uctype __uerngrange = __urngrange + 1; 00270 __tmp = (__uerngrange * operator() 00271 (__urng, param_type(0, __urange / __uerngrange))); 00272 __ret = __tmp + (__uctype(__urng()) - __urngmin); 00273 } 00274 while (__ret > __urange || __ret < __tmp); 00275 } 00276 else 00277 __ret = __uctype(__urng()) - __urngmin; 00278 00279 return __ret + __param.a(); 00280 } 00281 00282 00283 template<typename _IntType> 00284 template<typename _ForwardIterator, 00285 typename _UniformRandomNumberGenerator> 00286 void 00287 uniform_int_distribution<_IntType>:: 00288 __generate_impl(_ForwardIterator __f, _ForwardIterator __t, 00289 _UniformRandomNumberGenerator& __urng, 00290 const param_type& __param) 00291 { 00292 __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) 00293 typedef typename _UniformRandomNumberGenerator::result_type 00294 _Gresult_type; 00295 typedef typename std::make_unsigned<result_type>::type __utype; 00296 typedef typename std::common_type<_Gresult_type, __utype>::type 00297 __uctype; 00298 00299 const __uctype __urngmin = __urng.min(); 00300 const __uctype __urngmax = __urng.max(); 00301 const __uctype __urngrange = __urngmax - __urngmin; 00302 const __uctype __urange 00303 = __uctype(__param.b()) - __uctype(__param.a()); 00304 00305 __uctype __ret; 00306 00307 if (__urngrange > __urange) 00308 { 00309 if (__detail::_Power_of_2(__urngrange + 1) 00310 && __detail::_Power_of_2(__urange + 1)) 00311 { 00312 while (__f != __t) 00313 { 00314 __ret = __uctype(__urng()) - __urngmin; 00315 *__f++ = (__ret & __urange) + __param.a(); 00316 } 00317 } 00318 else 00319 { 00320 // downscaling 00321 const __uctype __uerange = __urange + 1; // __urange can be zero 00322 const __uctype __scaling = __urngrange / __uerange; 00323 const __uctype __past = __uerange * __scaling; 00324 while (__f != __t) 00325 { 00326 do 00327 __ret = __uctype(__urng()) - __urngmin; 00328 while (__ret >= __past); 00329 *__f++ = __ret / __scaling + __param.a(); 00330 } 00331 } 00332 } 00333 else if (__urngrange < __urange) 00334 { 00335 // upscaling 00336 /* 00337 Note that every value in [0, urange] 00338 can be written uniquely as 00339 00340 (urngrange + 1) * high + low 00341 00342 where 00343 00344 high in [0, urange / (urngrange + 1)] 00345 00346 and 00347 00348 low in [0, urngrange]. 00349 */ 00350 __uctype __tmp; // wraparound control 00351 while (__f != __t) 00352 { 00353 do 00354 { 00355 const __uctype __uerngrange = __urngrange + 1; 00356 __tmp = (__uerngrange * operator() 00357 (__urng, param_type(0, __urange / __uerngrange))); 00358 __ret = __tmp + (__uctype(__urng()) - __urngmin); 00359 } 00360 while (__ret > __urange || __ret < __tmp); 00361 *__f++ = __ret; 00362 } 00363 } 00364 else 00365 while (__f != __t) 00366 *__f++ = __uctype(__urng()) - __urngmin + __param.a(); 00367 } 00368 00369 _GLIBCXX_END_NAMESPACE_VERSION 00370 } // namespace std 00371 00372 #endif