You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
457 lines
13 KiB
457 lines
13 KiB
// Class template uniform_int_distribution -*- C++ -*-
|
|
|
|
// Copyright (C) 2009-2021 Free Software Foundation, Inc.
|
|
//
|
|
// This file is part of the GNU ISO C++ Library. This library is free
|
|
// software; you can redistribute it and/or modify it under the
|
|
// terms of the GNU General Public License as published by the
|
|
// Free Software Foundation; either version 3, or (at your option)
|
|
// any later version.
|
|
|
|
// This library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// Under Section 7 of GPL version 3, you are granted additional
|
|
// permissions described in the GCC Runtime Library Exception, version
|
|
// 3.1, as published by the Free Software Foundation.
|
|
|
|
// You should have received a copy of the GNU General Public License and
|
|
// a copy of the GCC Runtime Library Exception along with this program;
|
|
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
// <http://www.gnu.org/licenses/>.
|
|
|
|
/**
|
|
* @file bits/uniform_int_dist.h
|
|
* This is an internal header file, included by other library headers.
|
|
* Do not attempt to use it directly. @headername{random}
|
|
*/
|
|
|
|
#ifndef _GLIBCXX_BITS_UNIFORM_INT_DIST_H
|
|
#define _GLIBCXX_BITS_UNIFORM_INT_DIST_H
|
|
|
|
#include <type_traits>
|
|
#include <ext/numeric_traits.h>
|
|
#if __cplusplus > 201703L
|
|
# include <concepts>
|
|
#endif
|
|
#include <bits/concept_check.h> // __glibcxx_function_requires
|
|
|
|
namespace std _GLIBCXX_VISIBILITY(default)
|
|
{
|
|
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|
|
|
#ifdef __cpp_lib_concepts
|
|
/// Requirements for a uniform random bit generator.
|
|
template<typename _Gen>
|
|
concept uniform_random_bit_generator
|
|
= invocable<_Gen&> && unsigned_integral<invoke_result_t<_Gen&>>
|
|
&& requires
|
|
{
|
|
{ _Gen::min() } -> same_as<invoke_result_t<_Gen&>>;
|
|
{ _Gen::max() } -> same_as<invoke_result_t<_Gen&>>;
|
|
requires bool_constant<(_Gen::min() < _Gen::max())>::value;
|
|
};
|
|
#endif
|
|
|
|
namespace __detail
|
|
{
|
|
// Determine whether number is a power of two.
|
|
// This is true for zero, which is OK because we want _Power_of_2(n+1)
|
|
// to be true if n==numeric_limits<_Tp>::max() and so n+1 wraps around.
|
|
template<typename _Tp>
|
|
constexpr bool
|
|
_Power_of_2(_Tp __x)
|
|
{
|
|
return ((__x - 1) & __x) == 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Uniform discrete distribution for random numbers.
|
|
* A discrete random distribution on the range @f$[min, max]@f$ with equal
|
|
* probability throughout the range.
|
|
*/
|
|
template<typename _IntType = int>
|
|
class uniform_int_distribution
|
|
{
|
|
static_assert(std::is_integral<_IntType>::value,
|
|
"template argument must be an integral type");
|
|
|
|
public:
|
|
/** The type of the range of the distribution. */
|
|
typedef _IntType result_type;
|
|
/** Parameter type. */
|
|
struct param_type
|
|
{
|
|
typedef uniform_int_distribution<_IntType> distribution_type;
|
|
|
|
param_type() : param_type(0) { }
|
|
|
|
explicit
|
|
param_type(_IntType __a,
|
|
_IntType __b = __gnu_cxx::__int_traits<_IntType>::__max)
|
|
: _M_a(__a), _M_b(__b)
|
|
{
|
|
__glibcxx_assert(_M_a <= _M_b);
|
|
}
|
|
|
|
result_type
|
|
a() const
|
|
{ return _M_a; }
|
|
|
|
result_type
|
|
b() const
|
|
{ return _M_b; }
|
|
|
|
friend bool
|
|
operator==(const param_type& __p1, const param_type& __p2)
|
|
{ return __p1._M_a == __p2._M_a && __p1._M_b == __p2._M_b; }
|
|
|
|
friend bool
|
|
operator!=(const param_type& __p1, const param_type& __p2)
|
|
{ return !(__p1 == __p2); }
|
|
|
|
private:
|
|
_IntType _M_a;
|
|
_IntType _M_b;
|
|
};
|
|
|
|
public:
|
|
/**
|
|
* @brief Constructs a uniform distribution object.
|
|
*/
|
|
uniform_int_distribution() : uniform_int_distribution(0) { }
|
|
|
|
/**
|
|
* @brief Constructs a uniform distribution object.
|
|
*/
|
|
explicit
|
|
uniform_int_distribution(_IntType __a,
|
|
_IntType __b
|
|
= __gnu_cxx::__int_traits<_IntType>::__max)
|
|
: _M_param(__a, __b)
|
|
{ }
|
|
|
|
explicit
|
|
uniform_int_distribution(const param_type& __p)
|
|
: _M_param(__p)
|
|
{ }
|
|
|
|
/**
|
|
* @brief Resets the distribution state.
|
|
*
|
|
* Does nothing for the uniform integer distribution.
|
|
*/
|
|
void
|
|
reset() { }
|
|
|
|
result_type
|
|
a() const
|
|
{ return _M_param.a(); }
|
|
|
|
result_type
|
|
b() const
|
|
{ return _M_param.b(); }
|
|
|
|
/**
|
|
* @brief Returns the parameter set of the distribution.
|
|
*/
|
|
param_type
|
|
param() const
|
|
{ return _M_param; }
|
|
|
|
/**
|
|
* @brief Sets the parameter set of the distribution.
|
|
* @param __param The new parameter set of the distribution.
|
|
*/
|
|
void
|
|
param(const param_type& __param)
|
|
{ _M_param = __param; }
|
|
|
|
/**
|
|
* @brief Returns the inclusive lower bound of the distribution range.
|
|
*/
|
|
result_type
|
|
min() const
|
|
{ return this->a(); }
|
|
|
|
/**
|
|
* @brief Returns the inclusive upper bound of the distribution range.
|
|
*/
|
|
result_type
|
|
max() const
|
|
{ return this->b(); }
|
|
|
|
/**
|
|
* @brief Generating functions.
|
|
*/
|
|
template<typename _UniformRandomBitGenerator>
|
|
result_type
|
|
operator()(_UniformRandomBitGenerator& __urng)
|
|
{ return this->operator()(__urng, _M_param); }
|
|
|
|
template<typename _UniformRandomBitGenerator>
|
|
result_type
|
|
operator()(_UniformRandomBitGenerator& __urng,
|
|
const param_type& __p);
|
|
|
|
template<typename _ForwardIterator,
|
|
typename _UniformRandomBitGenerator>
|
|
void
|
|
__generate(_ForwardIterator __f, _ForwardIterator __t,
|
|
_UniformRandomBitGenerator& __urng)
|
|
{ this->__generate(__f, __t, __urng, _M_param); }
|
|
|
|
template<typename _ForwardIterator,
|
|
typename _UniformRandomBitGenerator>
|
|
void
|
|
__generate(_ForwardIterator __f, _ForwardIterator __t,
|
|
_UniformRandomBitGenerator& __urng,
|
|
const param_type& __p)
|
|
{ this->__generate_impl(__f, __t, __urng, __p); }
|
|
|
|
template<typename _UniformRandomBitGenerator>
|
|
void
|
|
__generate(result_type* __f, result_type* __t,
|
|
_UniformRandomBitGenerator& __urng,
|
|
const param_type& __p)
|
|
{ this->__generate_impl(__f, __t, __urng, __p); }
|
|
|
|
/**
|
|
* @brief Return true if two uniform integer distributions have
|
|
* the same parameters.
|
|
*/
|
|
friend bool
|
|
operator==(const uniform_int_distribution& __d1,
|
|
const uniform_int_distribution& __d2)
|
|
{ return __d1._M_param == __d2._M_param; }
|
|
|
|
private:
|
|
template<typename _ForwardIterator,
|
|
typename _UniformRandomBitGenerator>
|
|
void
|
|
__generate_impl(_ForwardIterator __f, _ForwardIterator __t,
|
|
_UniformRandomBitGenerator& __urng,
|
|
const param_type& __p);
|
|
|
|
param_type _M_param;
|
|
|
|
// Lemire's nearly divisionless algorithm.
|
|
// Returns an unbiased random number from __g downscaled to [0,__range)
|
|
// using an unsigned type _Wp twice as wide as unsigned type _Up.
|
|
template<typename _Wp, typename _Urbg, typename _Up>
|
|
static _Up
|
|
_S_nd(_Urbg& __g, _Up __range)
|
|
{
|
|
using _Up_traits = __gnu_cxx::__int_traits<_Up>;
|
|
using _Wp_traits = __gnu_cxx::__int_traits<_Wp>;
|
|
static_assert(!_Up_traits::__is_signed, "U must be unsigned");
|
|
static_assert(!_Wp_traits::__is_signed, "W must be unsigned");
|
|
static_assert(_Wp_traits::__digits == (2 * _Up_traits::__digits),
|
|
"W must be twice as wide as U");
|
|
|
|
// reference: Fast Random Integer Generation in an Interval
|
|
// ACM Transactions on Modeling and Computer Simulation 29 (1), 2019
|
|
// https://arxiv.org/abs/1805.10941
|
|
_Wp __product = _Wp(__g()) * _Wp(__range);
|
|
_Up __low = _Up(__product);
|
|
if (__low < __range)
|
|
{
|
|
_Up __threshold = -__range % __range;
|
|
while (__low < __threshold)
|
|
{
|
|
__product = _Wp(__g()) * _Wp(__range);
|
|
__low = _Up(__product);
|
|
}
|
|
}
|
|
return __product >> _Up_traits::__digits;
|
|
}
|
|
};
|
|
|
|
template<typename _IntType>
|
|
template<typename _UniformRandomBitGenerator>
|
|
typename uniform_int_distribution<_IntType>::result_type
|
|
uniform_int_distribution<_IntType>::
|
|
operator()(_UniformRandomBitGenerator& __urng,
|
|
const param_type& __param)
|
|
{
|
|
typedef typename _UniformRandomBitGenerator::result_type _Gresult_type;
|
|
typedef typename make_unsigned<result_type>::type __utype;
|
|
typedef typename common_type<_Gresult_type, __utype>::type __uctype;
|
|
|
|
constexpr __uctype __urngmin = _UniformRandomBitGenerator::min();
|
|
constexpr __uctype __urngmax = _UniformRandomBitGenerator::max();
|
|
static_assert( __urngmin < __urngmax,
|
|
"Uniform random bit generator must define min() < max()");
|
|
constexpr __uctype __urngrange = __urngmax - __urngmin;
|
|
|
|
const __uctype __urange
|
|
= __uctype(__param.b()) - __uctype(__param.a());
|
|
|
|
__uctype __ret;
|
|
if (__urngrange > __urange)
|
|
{
|
|
// downscaling
|
|
|
|
const __uctype __uerange = __urange + 1; // __urange can be zero
|
|
|
|
#if defined __UINT64_TYPE__ && defined __UINT32_TYPE__
|
|
#if __SIZEOF_INT128__
|
|
if _GLIBCXX17_CONSTEXPR (__urngrange == __UINT64_MAX__)
|
|
{
|
|
// __urng produces values that use exactly 64-bits,
|
|
// so use 128-bit integers to downscale to desired range.
|
|
__UINT64_TYPE__ __u64erange = __uerange;
|
|
__ret = _S_nd<unsigned __int128>(__urng, __u64erange);
|
|
}
|
|
else
|
|
#endif
|
|
if _GLIBCXX17_CONSTEXPR (__urngrange == __UINT32_MAX__)
|
|
{
|
|
// __urng produces values that use exactly 32-bits,
|
|
// so use 64-bit integers to downscale to desired range.
|
|
__UINT32_TYPE__ __u32erange = __uerange;
|
|
__ret = _S_nd<__UINT64_TYPE__>(__urng, __u32erange);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
// fallback case (2 divisions)
|
|
const __uctype __scaling = __urngrange / __uerange;
|
|
const __uctype __past = __uerange * __scaling;
|
|
do
|
|
__ret = __uctype(__urng()) - __urngmin;
|
|
while (__ret >= __past);
|
|
__ret /= __scaling;
|
|
}
|
|
}
|
|
else if (__urngrange < __urange)
|
|
{
|
|
// upscaling
|
|
/*
|
|
Note that every value in [0, urange]
|
|
can be written uniquely as
|
|
|
|
(urngrange + 1) * high + low
|
|
|
|
where
|
|
|
|
high in [0, urange / (urngrange + 1)]
|
|
|
|
and
|
|
|
|
low in [0, urngrange].
|
|
*/
|
|
__uctype __tmp; // wraparound control
|
|
do
|
|
{
|
|
const __uctype __uerngrange = __urngrange + 1;
|
|
__tmp = (__uerngrange * operator()
|
|
(__urng, param_type(0, __urange / __uerngrange)));
|
|
__ret = __tmp + (__uctype(__urng()) - __urngmin);
|
|
}
|
|
while (__ret > __urange || __ret < __tmp);
|
|
}
|
|
else
|
|
__ret = __uctype(__urng()) - __urngmin;
|
|
|
|
return __ret + __param.a();
|
|
}
|
|
|
|
|
|
template<typename _IntType>
|
|
template<typename _ForwardIterator,
|
|
typename _UniformRandomBitGenerator>
|
|
void
|
|
uniform_int_distribution<_IntType>::
|
|
__generate_impl(_ForwardIterator __f, _ForwardIterator __t,
|
|
_UniformRandomBitGenerator& __urng,
|
|
const param_type& __param)
|
|
{
|
|
__glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>)
|
|
typedef typename _UniformRandomBitGenerator::result_type _Gresult_type;
|
|
typedef typename make_unsigned<result_type>::type __utype;
|
|
typedef typename common_type<_Gresult_type, __utype>::type __uctype;
|
|
|
|
static_assert( __urng.min() < __urng.max(),
|
|
"Uniform random bit generator must define min() < max()");
|
|
|
|
constexpr __uctype __urngmin = __urng.min();
|
|
constexpr __uctype __urngmax = __urng.max();
|
|
constexpr __uctype __urngrange = __urngmax - __urngmin;
|
|
const __uctype __urange
|
|
= __uctype(__param.b()) - __uctype(__param.a());
|
|
|
|
__uctype __ret;
|
|
|
|
if (__urngrange > __urange)
|
|
{
|
|
if (__detail::_Power_of_2(__urngrange + 1)
|
|
&& __detail::_Power_of_2(__urange + 1))
|
|
{
|
|
while (__f != __t)
|
|
{
|
|
__ret = __uctype(__urng()) - __urngmin;
|
|
*__f++ = (__ret & __urange) + __param.a();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// downscaling
|
|
const __uctype __uerange = __urange + 1; // __urange can be zero
|
|
const __uctype __scaling = __urngrange / __uerange;
|
|
const __uctype __past = __uerange * __scaling;
|
|
while (__f != __t)
|
|
{
|
|
do
|
|
__ret = __uctype(__urng()) - __urngmin;
|
|
while (__ret >= __past);
|
|
*__f++ = __ret / __scaling + __param.a();
|
|
}
|
|
}
|
|
}
|
|
else if (__urngrange < __urange)
|
|
{
|
|
// upscaling
|
|
/*
|
|
Note that every value in [0, urange]
|
|
can be written uniquely as
|
|
|
|
(urngrange + 1) * high + low
|
|
|
|
where
|
|
|
|
high in [0, urange / (urngrange + 1)]
|
|
|
|
and
|
|
|
|
low in [0, urngrange].
|
|
*/
|
|
__uctype __tmp; // wraparound control
|
|
while (__f != __t)
|
|
{
|
|
do
|
|
{
|
|
constexpr __uctype __uerngrange = __urngrange + 1;
|
|
__tmp = (__uerngrange * operator()
|
|
(__urng, param_type(0, __urange / __uerngrange)));
|
|
__ret = __tmp + (__uctype(__urng()) - __urngmin);
|
|
}
|
|
while (__ret > __urange || __ret < __tmp);
|
|
*__f++ = __ret;
|
|
}
|
|
}
|
|
else
|
|
while (__f != __t)
|
|
*__f++ = __uctype(__urng()) - __urngmin + __param.a();
|
|
}
|
|
|
|
// operator!= and operator<< and operator>> are defined in <bits/random.h>
|
|
|
|
_GLIBCXX_END_NAMESPACE_VERSION
|
|
} // namespace std
|
|
|
|
#endif
|