1 #ifndef __UNIFORM_INT_DISTRIBUTION_HPP 2 #define __UNIFORM_INT_DISTRIBUTION_HPP 10 #include "cgs/meta.hpp" 13 #include <boost/integer.hpp> 14 #include <boost/random/uniform_int_distribution.hpp> 15 #include <boost/random/detail/uniform_int_float.hpp> 16 #include <boost/random/taus88.hpp> 17 #include <boost/random/mersenne_twister.hpp> 18 #include <boost/random/ranlux.hpp> 24 template<
typename int_type>
25 constexpr uint16_t
log2(int_type n) {
26 return ((n < 2) ? 1 : 1 +
log2(n / 2));
65 template<
class int_type =
int>
67 static_assert(std::is_integral<int_type>::value
68 && !std::is_same<int_type, bool>::value,
69 "'int_type' is not an integral type or it is bool");
100 _lowerLimit(lowerLimit),
101 _upperLimit(upperLimit) {
102 assert(_lowerLimit < _upperLimit);
110 int_type
a() const noexcept {
119 int_type
b() const noexcept {
134 return parameters0._lowerLimit == parameters1._lowerLimit
135 && parameters0._upperLimit == parameters1._upperLimit;
149 return !(parameters0 == parameters1);
178 _parameters(lowerLimit, upperLimit),
180 _range(upperLimit - lowerLimit),
181 _rangeBits(static_cast<uint16_t>(
std::ceil(
std::
log2(_range + 2)))),
182 _fallbackDistribution(lowerLimit, upperLimit) {};
205 return _parameters.a();
214 return _parameters.b();
231 void param(
const param_type& parameters) noexcept {
232 _parameters = parameters;
233 _offset = parameters.a();
234 _range = parameters.a() - parameters.b();
235 _rangeBits =
static_cast<uint16_t
>(std::ceil(
std::log2(_range + 2)));
236 _fallbackDistribution.param(parameters);
271 template<
typename uniform_random_number_generator>
274 using generator_type =
typename uniform_random_number_generator::result_type;
279 using unsigned_generator_type =
typename boost::uint_t<sizeof(generator_type) * CHAR_BIT>::fast;
282 using unsigned_result_type =
typename std::make_unsigned<result_type>::type;
285 constexpr
bool minMaxAvailable = cgs::is_constexpr<uniform_random_number_generator::min>()
286 && cgs::is_constexpr<uniform_random_number_generator::max>();
289 constexpr unsigned_generator_type generatorRange =
290 !minMaxAvailable || !std::is_integral<generator_type>::value ? 0
296 constexpr uint16_t generatorBits = std::is_integral<generator_type>::value
298 ? !minMaxAvailable ? static_cast<uint16_t>(0)
299 :
static_cast<uint16_t
>(
300 details::log2<unsigned_generator_type>(generatorRange + 1) - 1)
301 :
static_cast<uint16_t
>(
sizeof(generator_type) * CHAR_BIT);
303 constexpr uint16_t generatorTypeBits =
static_cast<uint16_t
>(
sizeof(generator_type) * CHAR_BIT);
309 constexpr uint16_t resultBits =
static_cast<uint16_t
>(
sizeof(
result_type) * CHAR_BIT);
313 using unsigned_double_width_result_type =
typename boost::uint_t<resultBits * 2>::fast;
314 using signed_double_width_result_type =
typename boost::int_t<resultBits * 2>::fast;
318 if constexpr (minMaxAvailable && std::is_integral<generator_type>::value) {
321 if constexpr (resultBits <= generatorBits) {
322 DBG1(<<
"Best Case: " <<
typeid(uniformRandomNumberGenerator).name() <<
" (" << static_cast<uint32_t>(_rangeBits) <<
" <= log2(" << static_cast<uint64_t>(generatorRange) <<
") = " << static_cast<uint32_t>(generatorBits) <<
")");
323 unsigned_generator_type x =
static_cast<unsigned_generator_type
>(uniformRandomNumberGenerator()
325 if constexpr (generatorBits !=
details::log2(generatorRange)) {
326 constexpr unsigned_generator_type bitMask =
327 gcem::pow<unsigned_generator_type, unsigned_generator_type>(2, generatorBits) - 1;
330 if constexpr (std::is_unsigned<result_type>::value && resultBits <= 32 && generatorBits <= 32) {
331 unsigned_double_width_result_type m =
static_cast<unsigned_double_width_result_type
>(x)
332 * (static_cast<unsigned_double_width_result_type>(_range)
333 +
static_cast<unsigned_double_width_result_type
>(1));
334 return static_cast<result_type>(_offset + (m >> generatorBits));
335 }
else if (std::is_unsigned<result_type>::value) {
336 __uint128_t m =
static_cast<__uint128_t
>(x)
337 * (static_cast<__uint128_t>(_range)
338 +
static_cast<__uint128_t
>(1));
339 return static_cast<result_type>(_offset + (m >> generatorBits));
340 }
else if (std::is_signed<result_type>::value && resultBits <= 32 && generatorBits <= 32) {
341 signed_double_width_result_type m =
static_cast<signed_double_width_result_type
>(x)
342 * (static_cast<signed_double_width_result_type>(_range)
343 +
static_cast<signed_double_width_result_type
>(1));
344 return static_cast<result_type>(_offset + (m >> generatorBits));
346 __int128_t m =
static_cast<__int128_t
>(x)
347 * (static_cast<__int128_t>(_range)
348 +
static_cast<__int128_t
>(1));
349 return static_cast<result_type>(_offset + (m >> generatorBits));
358 if (_rangeBits <= generatorBits) {
359 DBG1(<<
"176: " <<
typeid(uniformRandomNumberGenerator).name() <<
" (" << static_cast<uint32_t>(_rangeBits) <<
" <= log2(" << static_cast<uint64_t>(generatorRange) <<
") = " << static_cast<uint32_t>(generatorBits) <<
")");
360 unsigned_generator_type x =
static_cast<unsigned_generator_type
>(uniformRandomNumberGenerator()
362 if constexpr (generatorBits !=
details::log2(generatorRange)) {
363 constexpr unsigned_generator_type bitMask =
364 gcem::pow<unsigned_generator_type, unsigned_generator_type>(2, generatorBits) - 1;
367 if constexpr (std::is_unsigned<result_type>::value && resultBits <= 32 && generatorBits <= 32) {
368 unsigned_double_width_result_type m =
static_cast<unsigned_double_width_result_type
>(x)
369 * (static_cast<unsigned_double_width_result_type>(_range)
370 +
static_cast<unsigned_double_width_result_type
>(1));
371 return static_cast<result_type>(_offset + (m >> generatorBits));
372 }
else if (std::is_unsigned<result_type>::value) {
373 __uint128_t m =
static_cast<__uint128_t
>(x)
374 * (static_cast<__uint128_t>(_range)
375 +
static_cast<__uint128_t
>(1));
376 return static_cast<result_type>(_offset + (m >> generatorBits));
377 }
else if (std::is_signed<result_type>::value && resultBits <= 32 && generatorBits <= 32) {
378 signed_double_width_result_type m =
static_cast<signed_double_width_result_type
>(x)
379 * (static_cast<signed_double_width_result_type>(_range)
380 +
static_cast<signed_double_width_result_type
>(1));
381 return static_cast<result_type>(_offset + (m >> generatorBits));
383 __int128_t m =
static_cast<__int128_t
>(x)
384 * (static_cast<__int128_t>(_range)
385 +
static_cast<__int128_t
>(1));
386 return static_cast<result_type>(_offset + (m >> generatorBits));
393 DBG1(<<
"205: " <<
typeid(uniformRandomNumberGenerator).name() <<
" (" << static_cast<uint32_t>(_rangeBits) <<
" > log2(" << static_cast<uint64_t>(generatorRange) <<
") = " << static_cast<uint32_t>(generatorBits) <<
")");
394 return _fallbackDistribution(uniformRandomNumberGenerator);
400 unsigned_generator_type generatorRange;
401 if constexpr (std::is_integral<generator_type>::value) {
402 generatorRange = gcem::abs(
407 generatorRange = gcem::abs(
408 static_cast<unsigned_generator_type>(boost::random::detail::uniform_int_float<
409 uniform_random_number_generator>::
max())
410 - static_cast<unsigned_generator_type>(boost::random::detail::uniform_int_float<
411 uniform_random_number_generator>::
min()));
414 ?
static_cast<uint16_t
>(
sizeof(generator_type) * CHAR_BIT)
415 :
static_cast<uint16_t
>(std::floor(
std::log2(generatorRange + 1)));
419 if (_rangeBits <= generatorBits) {
420 DBG1(<<
"223: " <<
typeid(uniformRandomNumberGenerator).name() <<
" (" << static_cast<uint32_t>(_rangeBits) <<
" <= log2(" << static_cast<uint64_t>(generatorRange) <<
") = " << static_cast<uint32_t>(generatorBits) <<
")");
421 unsigned_generator_type x;
422 if constexpr (std::is_integral<generator_type>::value) {
423 x =
static_cast<unsigned_generator_type
>(uniformRandomNumberGenerator()
425 if (generatorBits < generatorTypeBits) {
426 unsigned_generator_type bitMask =
427 gcem::pow<unsigned_generator_type, unsigned_generator_type>(2, generatorBits) - 1;
431 boost::random::detail::uniform_int_float<uniform_random_number_generator> floatToInt(
432 uniformRandomNumberGenerator);
434 x =
static_cast<unsigned_generator_type
>(floatToInt());
436 if constexpr (std::is_unsigned<result_type>::value && resultBits <= 32 && generatorTypeBits <= 32) {
437 unsigned_double_width_result_type m =
static_cast<unsigned_double_width_result_type
>(x)
438 * (static_cast<unsigned_double_width_result_type>(_range)
439 +
static_cast<unsigned_double_width_result_type
>(1));
440 return static_cast<result_type>(_offset + (m >> generatorBits));
441 }
else if (std::is_unsigned<result_type>::value) {
442 __uint128_t m =
static_cast<__uint128_t
>(x)
443 * (static_cast<__uint128_t>(_range)
444 +
static_cast<__uint128_t
>(1));
445 return static_cast<result_type>(_offset + (m >> generatorBits));
446 }
else if (std::is_signed<result_type>::value && resultBits <= 32 && generatorTypeBits <= 32) {
447 signed_double_width_result_type m =
static_cast<signed_double_width_result_type
>(x)
448 * (static_cast<signed_double_width_result_type>(_range)
449 +
static_cast<signed_double_width_result_type
>(1));
450 return static_cast<result_type>(_offset + (m >> generatorBits));
452 __int128_t m =
static_cast<__int128_t
>(x)
453 * (static_cast<__int128_t>(_range)
454 +
static_cast<__int128_t
>(1));
455 return static_cast<result_type>(_offset + (m >> generatorBits));
462 DBG1(<<
"258: " <<
typeid(uniformRandomNumberGenerator).name() <<
" (" << static_cast<uint32_t>(_rangeBits) <<
" > log2(" << static_cast<uint64_t>(generatorRange) <<
") = " << static_cast<uint32_t>(generatorBits) <<
")");
463 return _fallbackDistribution(uniformRandomNumberGenerator);
479 return distribution0._parameters == distribution1._parameters;
493 return !(distribution0 == distribution1);
509 template<
class CharT,
class Traits,
class result_type>
510 friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& outputStream,
513 outputStream << distribution._parameters._a <<
"<" << distribution._parameters._b << std::endl;
534 template<
class CharT,
class Traits,
class result_type>
535 friend std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& inputStream,
542 inputStream >> lowerBound >> separator >> upperBound;
543 if (separator ==
'<') {
544 distribution.param(param_type(lowerBound, upperBound));
588 #endif // __UNIFORM_INT_DISTRIBUTION_HPP
const T max(const T x, const T y)
Definition: w_minmax.h:45
#define DBG1(a)
Definition: w_debug.h:251
const T min(const T x, const T y)
Definition: w_minmax.h:52