The piecewise distributions previously always generated an double value
out of provided generator, regardless of the result_type (template
parameter). This patch address above, by generating value of _RealType
by default.
Furthermore, this patch addresses LWG4052, "Bogus requirements for
piecewise_linear_distribution" issue, by converting the inputs
(from iterators, or provided weights functor) to RealType, instead
of double. See input_type test included in this patch.
For consistency the internal computations are now performed in RealType,
instead of double. This reduces the precision if the float it used,
however due the ABI compatibility, the double is still used for storage,
unless _GLIBCXX_USE_RESULT_TYPE_FOR_PIECEWISE_DENSITIES is defined (see
test_precision_depended in accessors.cc) test.
The above change leads to user-observable changes in the behavior or
distributions, both in produced outputs and number of calls to provided
generator performed per each element (see test_engine_calls in accessors.cc).
The pre-GCC17 behavior of distributions can be restored by defining
_GLIBCXX_USE_OLD_PIECEWISE_DISTRIBUTIONS (this also revers r17-xxxxxx
TODO update when merged). This is achieved by introduction of _CompType
that is either defined as double or _RealType.
To reduce the code duplication the __generate_one functions are introduced
for both distributions. They are used both by the operator() and
__generate_impl. The linear __generate_impl is now consistent with constant
version, and simply assigns the result of generator invocation for default
configuration.
Finally, this made result of stream operator for float/double param_type
of piecewise_linear_distribution consistent for 32bits/64bits. The
float specialization for constant distribution still produces different
result, however the calculated values are consistent when printed
as hexfloat.
libstdc++-v3/ChangeLog:
* doc/html/manual/using_macros.html: Regenrate.
* doc/xml/manual/using.xml
(_GLIBCXX_USE_OLD_PIECEWISE_DISTRIBUTIONS): Mention LWG4052.
* include/bits/random.h
(piecewise_constant_distribution::_CompType)
(piecewise_linear_distribution::_CompType): Define.
(piecewise_constant_distribution::__generate_one)
(piecewise_linear_distribution::__generate_one): Declare.
(piecewise_constant_distribution::_M_initialize2)
(piecewise_linear_distribution::__M_initialize2): Adjust
densities parameter to _CompType.
* include/bits/random.tcc (std::__normalize): Perform
computation in the type of factor parameter.
(piecewise_constant_distribution::_M_configure)
(piecewise_linear_distribution::_M_configure): Use _CompType.
(piecewise_constant_distribution::param_type::param_type)
(piecewise_constant_distribution::param_type::param_type):
Cast the inputs to the _CompType. Use _RealTyp e as input
weight functor.
(piecewise_constant_distribution::__generate_one)
(piecewise_linear_distribution::__generate_one): Extract
from operator() and use _CompType.
(piecewise_constant_distribution::operator())
(piecewise_constant_distribution::__generate_impl).
(piecewise_linear_distribution::operator()): Use __generate_one.
(piecewise_linear_distribution::__generate_impl): Optimize
_M_cp.empty() case and user __generate_one otherwise.
*
testsuite/26_numerics/random/piecewise_constant_distribution/operators/accessors.cc:
(test_precision_depended): Expand test to cover all constructors,
and inputs different from distribution result type.
(test_engine_calls): New tests.
*
testsuite/26_numerics/random/piecewise_linear_distribution/operators/accessors.cc:
Likewise.
*
testsuite/26_numerics/random/piecewise_constant_distribution/operators/serialize2.cc:
Update values to accommodate the change in precision for float.
Remove trailing whitespaces.
*
testsuite/26_numerics/random/piecewise_linear_distribution/operators/serialize2.cc:
Likewise, and enable float/double test for i686.
*
testsuite/26_numerics/random/piecewise_constant_distribution/cons/input_type.cc:
New test.
*
testsuite/26_numerics/random/piecewise_constant_distribution/cons/input_type_fallback_neg.cc:
New test.
*
testsuite/26_numerics/random/piecewise_linear_distribution/cons/input_type.cc:
New test.
*
testsuite/26_numerics/random/piecewise_linear_distribution/cons/input_type_fallback_neg.cc:
New test.
---
This depends on my previous two in-flight patches in the area:
* https://gcc.gnu.org/pipermail/libstdc++/2026-May/066674.html
* https://gcc.gnu.org/pipermail/libstdc++/2026-June/066750.html
Tested on x86_64-linux locally. *piecewise* test also passed with
all standard modes, -m32, debug and assertions.
OK for trunk?
.../doc/html/manual/using_macros.html | 5 +-
libstdc++-v3/doc/xml/manual/using.xml | 6 +-
libstdc++-v3/include/bits/random.h | 24 ++-
libstdc++-v3/include/bits/random.tcc | 198 +++++++++++-------
.../cons/input_type.cc | 52 +++++
.../cons/input_type_fallback_neg.cc | 55 +++++
.../operators/accessors.cc | 90 ++++++--
.../operators/serialize2.cc | 10 +-
.../cons/input_type.cc | 52 +++++
.../cons/input_type_fallback_neg.cc | 55 +++++
.../operators/accessors.cc | 95 +++++++--
.../operators/serialize2.cc | 15 +-
12 files changed, 520 insertions(+), 137 deletions(-)
create mode 100644
libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/cons/input_type.cc
create mode 100644
libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/cons/input_type_fallback_neg.cc
create mode 100644
libstdc++-v3/testsuite/26_numerics/random/piecewise_linear_distribution/cons/input_type.cc
create mode 100644
libstdc++-v3/testsuite/26_numerics/random/piecewise_linear_distribution/cons/input_type_fallback_neg.cc
diff --git a/libstdc++-v3/doc/html/manual/using_macros.html
b/libstdc++-v3/doc/html/manual/using_macros.html
index 2f54bf259fd..29a1e1567d1 100644
--- a/libstdc++-v3/doc/html/manual/using_macros.html
+++ b/libstdc++-v3/doc/html/manual/using_macros.html
@@ -164,8 +164,9 @@
their behavior to the state prior the implementation
of <a class="link"
href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82749" target="_top">
PR82749</a> (<a class="link"
href="https://cplusplus.github.io/LWG/lwg-defects.html#1439" target="_top">
- LWG1439</a>), and <a class="link"
href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125548" target="_top">
- PR125548</a>) in GCC-17.
+ LWG1439</a>), <a class="link"
href="https://cplusplus.github.io/LWG/lwg-defects.html#4052" target="_top">
+ LWG4052</a>, and <a class="link"
href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125548" target="_top">
+ PR125548</a> in GCC-17.
</p></dd><dt><span class="term"><code
class="code">_GLIBCXX_USE_RESULT_TYPE_FOR_PIECEWISE_DENSITIES</code></span></dt><dd><p>
Undefined by default. ABI-changing.
When defined, specializations of
diff --git a/libstdc++-v3/doc/xml/manual/using.xml
b/libstdc++-v3/doc/xml/manual/using.xml
index 1d4b32de30c..2a3ae1ca52f 100644
--- a/libstdc++-v3/doc/xml/manual/using.xml
+++ b/libstdc++-v3/doc/xml/manual/using.xml
@@ -1391,9 +1391,11 @@ g++ -Winvalid-pch -I. -include stdc++.h -H -g -O2
hello.cc -o test.exe
xlink:href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82749">
PR82749</link> (<link xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:href="https://cplusplus.github.io/LWG/lwg-defects.html#1439">
- LWG1439</link>), and <link xmlns:xlink="http://www.w3.org/1999/xlink"
+ LWG1439</link>), <link xmlns:xlink="http://www.w3.org/1999/xlink"
+ xlink:href="https://cplusplus.github.io/LWG/lwg-defects.html#4052">
+ LWG4052</link>, and <link xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125548">
- PR125548</link>) in GCC-17.
+ PR125548</link> in GCC-17.
</para>
</listitem></varlistentry>
<varlistentry><term><code>_GLIBCXX_USE_RESULT_TYPE_FOR_PIECEWISE_DENSITIES</code></term>
diff --git a/libstdc++-v3/include/bits/random.h
b/libstdc++-v3/include/bits/random.h
index 6fefa9e1c44..b5a7630935c 100644
--- a/libstdc++-v3/include/bits/random.h
+++ b/libstdc++-v3/include/bits/random.h
@@ -6470,6 +6470,11 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
using _StorageType
= __detail::__piecewise_distributions_storage_t<_RealType>;
+#ifdef _GLIBCXX_USE_OLD_PIECEWISE_DISTRIBUTIONS
+ using _CompType = double;
+#else
+ using _CompType = _RealType;
+#endif
public:
/** The type of the range of the distribution. */
@@ -6558,7 +6563,7 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
_M_configure();
void
- _M_initialize2(const _RealType* __ints, _RealType __den);
+ _M_initialize2(const _RealType* __ints, _CompType __den);
std::vector<_RealType> _M_int;
std::vector<_StorageType> _M_den;
@@ -6739,6 +6744,11 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
std::piecewise_constant_distribution<_RealType1>& __x);
private:
+ template<typename _AdaptedUniformRandomNumberGenerator>
+ result_type
+ __generate_one(_AdaptedUniformRandomNumberGenerator& __aurng,
+ const param_type& __param);
+
template<typename _ForwardIterator,
typename _UniformRandomNumberGenerator>
void
@@ -6781,6 +6791,11 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
using _StorageType
= __detail::__piecewise_distributions_storage_t<_RealType>;
+#ifdef _GLIBCXX_USE_OLD_PIECEWISE_DISTRIBUTIONS
+ using _CompType = double;
+#else
+ using _CompType = _RealType;
+#endif
public:
/** The type of the range of the distribution. */
@@ -6869,7 +6884,7 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
_M_configure();
void
- _M_initialize2(const _RealType* __ints, const _RealType* __dens);
+ _M_initialize2(const _RealType* __ints, const _CompType* __dens);
std::vector<_RealType> _M_int;
std::vector<_StorageType> _M_den;
@@ -7052,6 +7067,11 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
std::piecewise_linear_distribution<_RealType1>& __x);
private:
+ template<typename _AdaptedUniformRandomNumberGenerator>
+ result_type
+ __generate_one(_AdaptedUniformRandomNumberGenerator& __aurng,
+ const param_type& __param);
+
template<typename _ForwardIterator,
typename _UniformRandomNumberGenerator>
void
diff --git a/libstdc++-v3/include/bits/random.tcc
b/libstdc++-v3/include/bits/random.tcc
index bf402876eb2..070879b89f7 100644
--- a/libstdc++-v3/include/bits/random.tcc
+++ b/libstdc++-v3/include/bits/random.tcc
@@ -78,13 +78,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _InputIterator, typename _OutputIterator,
- typename _Tp>
+ typename _RealType>
_OutputIterator
__normalize(_InputIterator __first, _InputIterator __last,
- _OutputIterator __result, const _Tp& __factor)
+ _OutputIterator __result, const _RealType& __factor)
{
for (; __first != __last; ++__first, (void) ++__result)
- *__result = *__first / __factor;
+ *__result = _RealType(_RealType(*__first) / __factor);
return __result;
}
@@ -2947,28 +2947,30 @@ namespace __detail
piecewise_constant_distribution<_RealType>::param_type::
_M_configure()
{
- const double __sum = std::accumulate(_M_den.begin(),
- _M_den.end(), 0.0);
+ const _CompType __sum = std::accumulate(_M_den.begin(), _M_den.end(),
+ _CompType(0));
__glibcxx_assert(__sum > 0);
__detail::__normalize(_M_den.begin(), _M_den.end(), _M_den.begin(),
__sum);
+ _CompType __psum(0);
_M_cp.reserve(_M_den.size());
- std::partial_sum(_M_den.begin(), _M_den.end(),
- std::back_inserter(_M_cp));
+ for (_CompType __den : _M_den)
+ _M_cp.push_back(__psum += __den);
// Make sure the last cumulative probability is one.
- _M_cp[_M_cp.size() - 1] = 1.0;
+ _M_cp[_M_cp.size() - 1] = _CompType(1);
for (size_t __k = 0; __k < _M_den.size(); ++__k)
- _M_den[__k] /= _M_int[__k + 1] - _M_int[__k];
+ _M_den[__k] = _CompType(_CompType(_M_den[__k])
+ / (_M_int[__k + 1] - _M_int[__k]));
}
template<typename _RealType>
void
piecewise_constant_distribution<_RealType>::param_type::
- _M_initialize2(const _RealType* __ints, _RealType __den)
+ _M_initialize2(const _RealType* __ints, _CompType __den)
{
if (__ints[0] == _RealType(0) && __ints[1] == _RealType(1))
return;
@@ -3041,9 +3043,11 @@ namespace __detail
for (; __bbegin != __bend; ++__bbegin)
_M_int.push_back(*__bbegin);
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4052. Bogus requirements for piecewise_linear_distribution
_M_den.reserve(_M_int.size() - 1);
for (size_t __k = 0; __k < _M_int.size() - 1; (void)++__k, ++__wbegin)
- _M_den.push_back(*__wbegin);
+ _M_den.push_back(_CompType(*__wbegin));
_M_configure();
}
@@ -3057,10 +3061,21 @@ namespace __detail
if (__bl.size() < 2)
return;
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4052. Bogus requirements for piecewise_linear_distribution
+ auto __cfw = [&__fw](_RealType __n, _RealType __p)
+ {
+#ifdef _GLIBCXX_USE_OLD_PIECEWISE_DISTRIBUTIONS
+ return __fw(0.5 * (__n + __p));
+#else
+ return _RealType(__fw(_RealType(0.5 * (__n + __p))));
+#endif
+ };
+
if (__bl.size() == 2)
{
const _RealType *__ints = __bl.begin();
- _RealType __den = __fw(0.5 * (__ints[1] + __ints[0]));
+ _CompType __den = __cfw(__ints[1], __ints[0]);
_M_initialize2(__ints, __den);
return;
}
@@ -3068,7 +3083,7 @@ namespace __detail
_M_int = __bl;
_M_den.reserve(_M_int.size() - 1);
for (size_t __k = 0; __k < _M_int.size() - 1; ++__k)
- _M_den.push_back(__fw(0.5 * (_M_int[__k + 1] + _M_int[__k])));
+ _M_den.push_back(__cfw(_M_int[__k + 1], _M_int[__k]));
_M_configure();
}
@@ -3081,10 +3096,19 @@ namespace __detail
{
const size_t __n = __nw == 0 ? 1 : __nw;
const _RealType __delta = (__xmax - __xmin) / __n;
+ auto __cfw = [&__fw, __delta](_RealType __v)
+ {
+#ifdef _GLIBCXX_USE_OLD_PIECEWISE_DISTRIBUTIONS
+ return __fw(__v + 0.5 * __delta);
+#else
+ return _RealType(__fw(_RealType(__v + 0.5 * __delta)));
+#endif
+ };
+
if (__n == 1)
{
_RealType __ints[2] = { __xmin, __xmin + __delta };
- _RealType __den = __fw(__xmin + 0.5 * __delta);
+ _CompType __den = __cfw(__xmin);
_M_initialize2(__ints, __den);
return;
}
@@ -3095,11 +3119,26 @@ namespace __detail
_M_den.reserve(__n);
for (size_t __k = 0; __k < __nw; ++__k)
- _M_den.push_back(__fw(_M_int[__k] + 0.5 * __delta));
+ _M_den.push_back(__cfw(_M_int[__k]));
_M_configure();
}
+ template<typename _RealType>
+ template<typename _AdaptedUniformRandomNumberGenerator>
+ typename piecewise_constant_distribution<_RealType>::result_type
+ piecewise_constant_distribution<_RealType>::
+ __generate_one(_AdaptedUniformRandomNumberGenerator& __aurng,
+ const param_type& __param)
+ {
+ const _CompType __p = __aurng();
+ auto __pos = std::lower_bound(__param._M_cp.begin(),
+ __param._M_cp.end(), __p);
+ const size_t __i = __pos - __param._M_cp.begin();
+ const _CompType __pref = __i > 0 ? __param._M_cp[__i - 1] :
_CompType(0);
+ return __param._M_int[__i] + (__p - __pref) /
_CompType(__param._M_den[__i]);
+ }
+
template<typename _RealType>
template<typename _UniformRandomNumberGenerator>
typename piecewise_constant_distribution<_RealType>::result_type
@@ -3107,20 +3146,13 @@ namespace __detail
operator()(_UniformRandomNumberGenerator& __urng,
const param_type& __param)
{
- __detail::_Adaptor<_UniformRandomNumberGenerator, double>
+ __detail::_Adaptor<_UniformRandomNumberGenerator, _CompType>
__aurng(__urng);
- const double __p = __aurng();
if (__param._M_cp.empty())
- return __p;
-
- auto __pos = std::lower_bound(__param._M_cp.begin(),
- __param._M_cp.end(), __p);
- const size_t __i = __pos - __param._M_cp.begin();
+ return __aurng();
- const double __pref = __i > 0 ? __param._M_cp[__i - 1] : 0.0;
-
- return __param._M_int[__i] + (__p - __pref) / __param._M_den[__i];
+ return __generate_one(__aurng, __param);
}
template<typename _RealType>
@@ -3133,29 +3165,15 @@ namespace __detail
const param_type& __param)
{
__glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>)
- __detail::_Adaptor<_UniformRandomNumberGenerator, double>
+ __detail::_Adaptor<_UniformRandomNumberGenerator, _CompType>
__aurng(__urng);
if (__param._M_cp.empty())
- {
- while (__f != __t)
- *__f++ = __aurng();
- return;
- }
-
- while (__f != __t)
- {
- const double __p = __aurng();
-
- auto __pos = std::lower_bound(__param._M_cp.begin(),
- __param._M_cp.end(), __p);
- const size_t __i = __pos - __param._M_cp.begin();
-
- const double __pref = __i > 0 ? __param._M_cp[__i - 1] : 0.0;
-
- *__f++ = (__param._M_int[__i]
- + (__p - __pref) / __param._M_den[__i]);
- }
+ while (__f != __t)
+ *__f++ = __aurng();
+ else
+ while (__f != __t)
+ *__f++ = __generate_one(__urng, __param);
}
template<typename _RealType, typename _CharT, typename _Traits>
@@ -3230,15 +3248,17 @@ namespace __detail
piecewise_linear_distribution<_RealType>::param_type::
_M_configure()
{
- double __sum = 0.0;
+ _CompType __sum = 0.0;
_M_cp.reserve(_M_int.size() - 1);
_M_m.reserve(_M_int.size() - 1);
for (size_t __k = 0; __k < _M_int.size() - 1; ++__k)
{
const _RealType __delta = _M_int[__k + 1] - _M_int[__k];
- __sum += 0.5 * (_M_den[__k + 1] + _M_den[__k]) * __delta;
+ __sum
+ += 0.5 * (_CompType(_M_den[__k + 1]) + _CompType(_M_den[__k])) *
__delta;
_M_cp.push_back(__sum);
- _M_m.push_back((_M_den[__k + 1] - _M_den[__k]) / __delta);
+ _M_m.push_back(
+ (_CompType(_M_den[__k + 1]) - _CompType(_M_den[__k])) / __delta);
}
__glibcxx_assert(__sum > 0);
@@ -3251,13 +3271,13 @@ namespace __detail
__detail::__normalize(_M_m.begin(), _M_m.end(), _M_m.begin(), __sum);
// Make sure the last cumulative probablility is one.
- _M_cp[_M_cp.size() - 1] = 1.0;
+ _M_cp[_M_cp.size() - 1] = _CompType(1);
}
template<typename _RealType>
void
piecewise_linear_distribution<_RealType>::param_type::
- _M_initialize2(const _RealType* __ints, const _RealType* __dens)
+ _M_initialize2(const _RealType* __ints, const _CompType* __dens)
{
if (__ints[0] == _RealType(0)
&& __ints[1] == _RealType(1)
@@ -3288,7 +3308,7 @@ namespace __detail
if (__bbegin == __bend)
{
- _RealType __dens[2];
+ _CompType __dens[2];
__dens[0] = *__wbegin;
++__wbegin;
__dens[1] = *__wbegin;
@@ -3314,9 +3334,11 @@ namespace __detail
for (; __bbegin != __bend; ++__bbegin)
_M_int.push_back(*__bbegin);
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4052. Bogus requirements for piecewise_linear_distribution
_M_den.reserve(_M_int.size());
for (size_t __i = 0; __i < _M_int.size(); (void)++__i, ++__wbegin)
- _M_den.push_back(*__wbegin);
+ _M_den.push_back(_CompType(*__wbegin));
_M_configure();
}
@@ -3333,7 +3355,7 @@ namespace __detail
if (__bl.size() == 2)
{
const _RealType *__ints = __bl.begin();
- _RealType __den[2];
+ _CompType __den[2];
__den[0] = __fw(__ints[0]);
__den[1] = __fw(__ints[1]);
_M_initialize2(__ints, __den);
@@ -3343,7 +3365,7 @@ namespace __detail
_M_int = __bl;
_M_den.reserve(__bl.size());
for (_RealType __b : __bl)
- _M_den.push_back(__fw(__b));
+ _M_den.push_back(_CompType(__fw(__b)));
_M_configure();
}
@@ -3356,18 +3378,20 @@ namespace __detail
const size_t __n = __nw == 0 ? 1 : __nw;
const _RealType __delta = (__xmax - __xmin) / __n;
const auto __cfw = [&] (_RealType __v)
- {
+ {
#ifdef _GLIBCXX_USE_OLD_PIECEWISE_DISTRIBUTIONS
- return __fw(__v + __delta);
+ return __fw(__v + __delta);
#else
- return __fw(__v);
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4052. Bogus requirements for piecewise_linear_distribution
+ return _RealType(__fw(__v));
#endif
- };
+ };
if (__n == 1)
{
_RealType __ints[2] = { __xmin, __xmin + __delta };
- _RealType __dens[2];
+ _CompType __dens[2];
__dens[0] = __cfw(__ints[0]);
__dens[1] = __cfw(__ints[1]);
_M_initialize2(__ints, __dens);
@@ -3386,39 +3410,49 @@ namespace __detail
}
template<typename _RealType>
- template<typename _UniformRandomNumberGenerator>
+ template<typename _AdaptedUniformRandomNumberGenerator>
typename piecewise_linear_distribution<_RealType>::result_type
piecewise_linear_distribution<_RealType>::
- operator()(_UniformRandomNumberGenerator& __urng,
- const param_type& __param)
+ __generate_one(_AdaptedUniformRandomNumberGenerator& __aurng,
+ const param_type& __param)
{
- __detail::_Adaptor<_UniformRandomNumberGenerator, double>
- __aurng(__urng);
-
- const double __p = __aurng();
- if (__param._M_cp.empty())
- return __p;
-
+ const _CompType __p = __aurng();
auto __pos = std::lower_bound(__param._M_cp.begin(),
__param._M_cp.end(), __p);
const size_t __i = __pos - __param._M_cp.begin();
- const double __pref = __i > 0 ? __param._M_cp[__i - 1] : 0.0;
+ const _CompType __pref = __i > 0 ? __param._M_cp[__i - 1] : 0.0;
- const double __a = 0.5 * __param._M_m[__i];
- const double __b = __param._M_den[__i];
- const double __cm = __p - __pref;
+ const _CompType __a = 0.5 * __param._M_m[__i];
+ const _CompType __b = __param._M_den[__i];
+ const _CompType __cm = __p - __pref;
_RealType __x = __param._M_int[__i];
if (__a == 0)
__x += __cm / __b;
else
{
- const double __d = __b * __b + 4.0 * __a * __cm;
+ const _CompType __d = __b * __b + 4.0 * __a * __cm;
__x += 0.5 * (std::sqrt(__d) - __b) / __a;
- }
+ }
+ return __x;
+ }
+
- return __x;
+ template<typename _RealType>
+ template<typename _UniformRandomNumberGenerator>
+ typename piecewise_linear_distribution<_RealType>::result_type
+ piecewise_linear_distribution<_RealType>::
+ operator()(_UniformRandomNumberGenerator& __urng,
+ const param_type& __param)
+ {
+ __detail::_Adaptor<_UniformRandomNumberGenerator, _CompType>
+ __aurng(__urng);
+
+ if (__param._M_cp.empty())
+ return __aurng();
+
+ return __generate_one(__aurng, __param);
}
template<typename _RealType>
@@ -3431,9 +3465,15 @@ namespace __detail
const param_type& __param)
{
__glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>)
- // We could duplicate everything from operator()...
- while (__f != __t)
- *__f++ = this->operator()(__urng, __param);
+ __detail::_Adaptor<_UniformRandomNumberGenerator, _CompType>
+ __aurng(__urng);
+
+ if (__param._M_cp.empty())
+ while (__f != __t)
+ *__f++ = __aurng();
+ else
+ while (__f != __t)
+ *__f++ = __generate_one(__urng, __param);
}
template<typename _RealType, typename _CharT, typename _Traits>
diff --git
a/libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/cons/input_type.cc
b/libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/cons/input_type.cc
new file mode 100644
index 00000000000..ebd548eb5c4
--- /dev/null
+++
b/libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/cons/input_type.cc
@@ -0,0 +1,52 @@
+// { dg-do compile { target c++11 } }
+// { dg-require-cstdint "" }
+
+#include <random>
+
+template<typename RealType>
+struct OnlyConv
+{
+ long double v;
+
+ template<typename DestType>
+ operator DestType() const
+ {
+ static_assert(std::is_same<DestType, RealType>::value);
+ return v;
+ }
+};
+
+template<typename RealType>
+struct OnlyCall
+{
+ template<typename SourceType>
+ OnlyConv<RealType> operator()(SourceType src)
+ {
+ static_assert(std::is_same<SourceType, RealType>::value);
+ return OnlyConv<RealType>{src};
+ }
+};
+
+template<typename RealType>
+void
+test()
+{
+ std::initializer_list<RealType> invs{0, 1, 2};
+ OnlyConv<RealType> weights[2]{1, 2};
+
+ std::piecewise_constant_distribution<RealType>
+ from_iter(invs.begin(), invs.end(), weights);
+
+ std::piecewise_constant_distribution<RealType>
+ from_init_list(invs, OnlyCall<RealType>());
+
+ std::piecewise_constant_distribution<RealType>
+ from_count(2, 0, 2, OnlyCall<RealType>());
+}
+
+int main()
+{
+ test<float>();
+ test<double>();
+ test<long double>();
+}
diff --git
a/libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/cons/input_type_fallback_neg.cc
b/libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/cons/input_type_fallback_neg.cc
new file mode 100644
index 00000000000..6fb04ef7655
--- /dev/null
+++
b/libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/cons/input_type_fallback_neg.cc
@@ -0,0 +1,55 @@
+// { dg-options "-D_GLIBCXX_USE_OLD_PIECEWISE_DISTRIBUTIONS" }
+// { dg-do compile { target c++11 } }
+// { dg-require-cstdint "" }
+
+#include <random>
+
+template<typename RealType>
+struct OnlyConv
+{
+ long double v;
+
+ template<typename DestType>
+ operator DestType() const
+ {
+ static_assert(std::is_same<DestType, RealType>::value);
+ return v;
+ }
+};
+
+template<typename RealType>
+struct OnlyCall
+{
+ template<typename SourceType>
+ OnlyConv<RealType> operator()(SourceType src)
+ {
+ static_assert(std::is_same<SourceType, RealType>::value);
+ return OnlyConv<RealType>{src};
+ }
+};
+
+template<typename RealType>
+void
+test()
+{
+ std::initializer_list<RealType> invs{0, 1, 2};
+ OnlyConv<RealType> weights[2]{1, 2};
+
+ std::piecewise_constant_distribution<RealType>
+ from_iter(invs.begin(), invs.end(), weights);
+
+ std::piecewise_constant_distribution<RealType>
+ from_init_list(invs, OnlyCall<RealType>());
+
+ std::piecewise_constant_distribution<RealType>
+ from_count(2, 0, 2, OnlyCall<RealType>());
+}
+
+int main()
+{
+ test<float>(); // { dg-error "here" }
+ test<double>();
+ test<long double>(); // { dg-error "here" }
+}
+
+// { dg-prune-output "static assertion failed" }
diff --git
a/libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/operators/accessors.cc
b/libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/operators/accessors.cc
index db4193847e3..15fb6821749 100644
---
a/libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/operators/accessors.cc
+++
b/libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/operators/accessors.cc
@@ -33,39 +33,84 @@ test_exact()
VERIFY( density[4] == RealType(0.5 / 8.0) );
}
-template<typename RealType>
+template<typename InputType, typename DistType = InputType>
void
test_precision_depended()
{
constexpr bool preserved
-#ifdef _GLIBCXX_USE_RESULT_TYPE_FOR_PIECEWISE_DENSITIES
- = true;
+#ifdef _GLIBCXX_USE_OLD_PIECEWISE_DISTRIBUTIONS
+ = sizeof(InputType) <= sizeof(double);
+#elifdef _GLIBCXX_USE_RESULT_TYPE_FOR_PIECEWISE_DENSITIES
+ = sizeof(InputType) <= sizeof(DistType);
#else
- = sizeof(RealType) <= sizeof(double);
+ // input is converted to DistType and stored in double
+ = (sizeof(InputType) <= sizeof(DistType))
+ && (sizeof(InputType) <= sizeof(double));
#endif
- RealType x[3]{0.0, 0.5, 1.0};
- constexpr RealType step
- = std::numeric_limits<RealType>::epsilon();
- RealType wt[2]{RealType(1) - step, RealType(1) + step};
+ std::initializer_list<DistType> x{0.0, 0.5, 1.0};
+ constexpr InputType step
+ = std::numeric_limits<InputType>::epsilon();
+ InputType wt[2]{InputType(1) - step, InputType(1) + step};
- std::piecewise_constant_distribution<RealType>
- u(std::begin(x), std::end(x), wt);
+ using Distribution = std::piecewise_constant_distribution<DistType>;
+ auto validate = [&wt](const Distribution& dist)
+ {
+ const std::vector<DistType>& interval = dist.intervals();
+ VERIFY( interval.size() == 3 );
+ VERIFY( interval[0] == DistType(0.0) );
+ VERIFY( interval[2] == DistType(1.0) );
- const std::vector<RealType>& interval = u.intervals();
- VERIFY( interval.size() == 3 );
- VERIFY( interval[0] == RealType(0.0) );
- VERIFY( interval[2] == RealType(1.0) );
+#ifdef _GLIBCXX_USE_OLD_PIECEWISE_DISTRIBUTIONS
+ const std::vector<double>& density = dist.densities();
+#else
+ const std::vector<DistType>& density = dist.densities();
+#endif
+
+ VERIFY( density.size() == 2 );
+ VERIFY( density[0] == (preserved ? wt[0] : InputType(1)) );
+ VERIFY( density[1] == (preserved ? wt[1] : InputType(1)) );
+ };
+
+ Distribution from_iter(x.begin(), x.end(), wt);
+ validate(from_iter);
+ auto wf = [&wt](DistType v)
+ { return wt[int(v / 0.5)]; };
+
+ Distribution from_init_list(x, wf);
+ validate(from_init_list);
+
+ Distribution from_count(2, InputType(0), InputType(1), wf);
+ validate(from_count);
+}
+
+template<typename RealType, typename URBG = std::mt19937>
+void
+test_engine_calls()
+{
+ constexpr std::size_t bits = __builtin_popcountg(URBG::max() - URBG::min());
+ constexpr std::size_t calls
#ifdef _GLIBCXX_USE_OLD_PIECEWISE_DISTRIBUTIONS
- const std::vector<double>& density = u.densities();
+ = (std::numeric_limits<double>::digits + bits - 1) / bits;
#else
- const std::vector<RealType>& density = u.densities();
+ = (std::numeric_limits<RealType>::digits + bits - 1) / bits;
#endif
- VERIFY( density.size() == 2 );
- VERIFY( density[0] == (preserved ? wt[0] : RealType(1)) );
- VERIFY( density[1] == (preserved ? wt[1] : RealType(1)) );
+ struct wrapper : URBG
+ {
+ typename URBG::result_type operator()()
+ {
+ ++num_calls;
+ return URBG::operator()();
+ }
+ std::size_t num_calls = 0;
+ };
+
+ wrapper eng;
+ std::piecewise_constant_distribution<RealType> u;
+ u(eng);
+ VERIFY(eng.num_calls == calls);
}
int main()
@@ -79,5 +124,12 @@ int main()
test_precision_depended<double>();
test_precision_depended<long double>();
+ test_precision_depended<double, float>();
+ test_precision_depended<long double, float>();
+ test_precision_depended<long double, double>();
+
+ test_engine_calls<float>();
+ test_engine_calls<double>();
+ test_engine_calls<long double>();
return 0;
}
diff --git
a/libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/operators/serialize2.cc
b/libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/operators/serialize2.cc
index 60838d7396b..dae9f4aaf34 100644
---
a/libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/operators/serialize2.cc
+++
b/libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/operators/serialize2.cc
@@ -38,7 +38,7 @@ test_default()
"1 0.00000000000000000e+00 1.00000000000000000e+00
1.00000000000000000e+00";
VERIFY( res == expected );
break;
- case 64: // ieee80
+ case 64: // ieee80
expected =
"1 0.000000000000000000000e+00 1.000000000000000000000e+00
1.000000000000000000000e+00";
VERIFY( res == expected );
@@ -74,19 +74,19 @@ test_custom()
case 24: // ieee32
expected =
"3 0.000000000e+00 3.333333433e-01 6.666666865e-01 1.000000000e+00"
- " 7.777777281e-01 9.999999702e-01 1.222222322e+00";
+ " 7.777777314e-01 1.000000000e+00 1.222222328e+00";
VERIFY( res == expected );
break;
case 53: // ieee64
expected =
"3 0.00000000000000000e+00 3.33333333333333315e-01
6.66666666666666630e-01 1.00000000000000000e+00"
- " 7.77777777777777901e-01 1.00000000000000000e+00
1.22222222222222210e+00";
+ " 7.77777777777777901e-01 1.00000000000000000e+00
1.22222222222222210e+00";
VERIFY( res == expected );
break;
- case 64: // ieee80
+ case 64: // ieee80
expected =
"3 0.000000000000000000000e+00 3.333333333333333333424e-01
6.666666666666666666847e-01 1.000000000000000000000e+00"
- " 7.777777777777779011359e-01 1.000000000000000000000e+00
1.222222222222222098864e+00";
+ " 7.777777777777779011359e-01 1.000000000000000000000e+00
1.222222222222222098864e+00";
VERIFY( res == expected );
break;
default:
diff --git
a/libstdc++-v3/testsuite/26_numerics/random/piecewise_linear_distribution/cons/input_type.cc
b/libstdc++-v3/testsuite/26_numerics/random/piecewise_linear_distribution/cons/input_type.cc
new file mode 100644
index 00000000000..3c5b717e0f2
--- /dev/null
+++
b/libstdc++-v3/testsuite/26_numerics/random/piecewise_linear_distribution/cons/input_type.cc
@@ -0,0 +1,52 @@
+// { dg-do compile { target c++11 } }
+// { dg-require-cstdint "" }
+
+#include <random>
+
+template<typename RealType>
+struct OnlyConv
+{
+ long double v;
+
+ template<typename DestType>
+ operator DestType() const
+ {
+ static_assert(std::is_same<DestType, RealType>::value);
+ return v;
+ }
+};
+
+template<typename RealType>
+struct OnlyCall
+{
+ template<typename SourceType>
+ OnlyConv<RealType> operator()(SourceType src)
+ {
+ static_assert(std::is_same<SourceType, RealType>::value);
+ return OnlyConv<RealType>{src};
+ }
+};
+
+template<typename RealType>
+void
+test()
+{
+ std::initializer_list<RealType> invs{0, 1, 2};
+ OnlyConv<RealType> weights[3]{1, 2, 3};
+
+ std::piecewise_linear_distribution<RealType>
+ from_iter(invs.begin(), invs.end(), weights);
+
+ std::piecewise_linear_distribution<RealType>
+ from_init_list(invs, OnlyCall<RealType>());
+
+ std::piecewise_linear_distribution<RealType>
+ from_count(2, 0, 2, OnlyCall<RealType>());
+}
+
+int main()
+{
+ test<float>();
+ test<double>();
+ test<long double>();
+}
diff --git
a/libstdc++-v3/testsuite/26_numerics/random/piecewise_linear_distribution/cons/input_type_fallback_neg.cc
b/libstdc++-v3/testsuite/26_numerics/random/piecewise_linear_distribution/cons/input_type_fallback_neg.cc
new file mode 100644
index 00000000000..48ae22b87bb
--- /dev/null
+++
b/libstdc++-v3/testsuite/26_numerics/random/piecewise_linear_distribution/cons/input_type_fallback_neg.cc
@@ -0,0 +1,55 @@
+// { dg-options "-D_GLIBCXX_USE_OLD_PIECEWISE_DISTRIBUTIONS" }
+// { dg-do compile { target c++11 } }
+// { dg-require-cstdint "" }
+
+#include <random>
+
+template<typename RealType>
+struct OnlyConv
+{
+ long double v;
+
+ template<typename DestType>
+ operator DestType() const
+ {
+ static_assert(std::is_same<DestType, RealType>::value);
+ return v;
+ }
+};
+
+template<typename RealType>
+struct OnlyCall
+{
+ template<typename SourceType>
+ OnlyConv<RealType> operator()(SourceType src)
+ {
+ static_assert(std::is_same<SourceType, RealType>::value);
+ return OnlyConv<RealType>{src};
+ }
+};
+
+template<typename RealType>
+void
+test()
+{
+ std::initializer_list<RealType> invs{0, 1, 2};
+ OnlyConv<RealType> weights[3]{1, 2, 3};
+
+ std::piecewise_linear_distribution<RealType>
+ from_iter(invs.begin(), invs.end(), weights);
+
+ std::piecewise_linear_distribution<RealType>
+ from_init_list(invs, OnlyCall<RealType>());
+
+ std::piecewise_linear_distribution<RealType>
+ from_count(2, 0, 2, OnlyCall<RealType>());
+}
+
+int main()
+{
+ test<float>(); // { dg-error "here" }
+ test<double>();
+ test<long double>(); // { dg-error "here" }
+}
+
+// { dg-prune-output "static assertion failed" }
diff --git
a/libstdc++-v3/testsuite/26_numerics/random/piecewise_linear_distribution/operators/accessors.cc
b/libstdc++-v3/testsuite/26_numerics/random/piecewise_linear_distribution/operators/accessors.cc
index 0a13e0fd9e2..5da22fc1011 100644
---
a/libstdc++-v3/testsuite/26_numerics/random/piecewise_linear_distribution/operators/accessors.cc
+++
b/libstdc++-v3/testsuite/26_numerics/random/piecewise_linear_distribution/operators/accessors.cc
@@ -34,40 +34,88 @@ test_exact()
VERIFY( density[5] == RealType(2.0 / 8.0) );
}
-template<typename RealType>
+template<typename InputType, typename DistType = InputType>
void
test_precision_depended()
{
constexpr bool preserved
-#ifdef _GLIBCXX_USE_RESULT_TYPE_FOR_PIECEWISE_DENSITIES
- = true;
+#ifdef _GLIBCXX_USE_OLD_PIECEWISE_DISTRIBUTIONS
+ = sizeof(InputType) <= sizeof(double);
+#elifdef _GLIBCXX_USE_RESULT_TYPE_FOR_PIECEWISE_DENSITIES
+ = sizeof(InputType) <= sizeof(DistType);
#else
- = sizeof(RealType) <= sizeof(double);
+ // input is converted to DistType and stored in double
+ = (sizeof(InputType) <= sizeof(DistType))
+ && (sizeof(InputType) <= sizeof(double));
#endif
- RealType x[3]{0.0, 0.5, 1.0};
- constexpr RealType step
- = std::numeric_limits<RealType>::epsilon() * 2;
- RealType wt[3]{RealType(1) - step, RealType(1), RealType(1) + step};
+ std::initializer_list<DistType> x{0.0, 0.5, 1.0};
+ constexpr InputType step
+ = std::numeric_limits<InputType>::epsilon() * 2;
+ InputType wt[3]{InputType(1) - step, InputType(1), InputType(1) + step};
- std::piecewise_linear_distribution<RealType>
- u(std::begin(x), std::end(x), wt);
+ using Distribution = std::piecewise_linear_distribution<DistType>;
+ auto validate = [&wt](const Distribution& dist)
+ {
+ const std::vector<DistType>& interval = dist.intervals();
+ VERIFY( interval.size() == 3 );
+ VERIFY( interval[0] == DistType(0.0) );
+ VERIFY( interval[2] == DistType(1.0) );
- const std::vector<RealType>& interval = u.intervals();
- VERIFY( interval.size() == 3 );
- VERIFY( interval[0] == RealType(0.0) );
- VERIFY( interval[2] == RealType(1.0) );
+#ifdef _GLIBCXX_USE_OLD_PIECEWISE_DISTRIBUTIONS
+ const std::vector<double>& density = dist.densities();
+#else
+ const std::vector<DistType>& density = dist.densities();
+#endif
+
+ VERIFY( density.size() == 3 );
+ VERIFY( density[0] == (preserved ? wt[0] : InputType(1)) );
+ VERIFY( density[1] == InputType(1) );
+ VERIFY( density[2] == (preserved ? wt[2] : InputType(1)) );
+ };
+
+ Distribution from_iter(x.begin(), x.end(), wt);
+ validate(from_iter);
+ auto wf = [&wt](DistType v)
+ { return wt[int(v / 0.5)]; };
+
+ Distribution from_init_list(x, wf);
+ validate(from_init_list);
+
+#ifndef _GLIBCXX_USE_OLD_PIECEWISE_DISTRIBUTIONS
+ // PR125548 leads to incorrect densities being used
+ Distribution from_count(2, InputType(0), InputType(1), wf);
+ validate(from_count);
+#endif
+}
+
+template<typename RealType, typename URBG = std::mt19937>
+void
+test_engine_calls()
+{
+ constexpr std::size_t bits = __builtin_popcountg(URBG::max() - URBG::min());
+ constexpr std::size_t calls
#ifdef _GLIBCXX_USE_OLD_PIECEWISE_DISTRIBUTIONS
- const std::vector<double>& density = u.densities();
+ = (std::numeric_limits<double>::digits + bits - 1) / bits;
#else
- const std::vector<RealType>& density = u.densities();
+ = (std::numeric_limits<RealType>::digits + bits - 1) / bits;
#endif
- VERIFY( density.size() == 3 );
- VERIFY( density[0] == (preserved ? wt[0] : RealType(1)) );
- VERIFY( density[1] == RealType(1) );
- VERIFY( density[2] == (preserved ? wt[2] : RealType(1)) );
+ struct wrapper : URBG
+ {
+ typename URBG::result_type operator()()
+ {
+ ++num_calls;
+ return URBG::operator()();
+ }
+ std::size_t num_calls = 0;
+ };
+
+ wrapper eng;
+ std::piecewise_linear_distribution<RealType> u;
+ u(eng);
+ VERIFY(eng.num_calls == calls);
}
int main()
@@ -81,5 +129,12 @@ int main()
test_precision_depended<double>();
test_precision_depended<long double>();
+ test_precision_depended<double, float>();
+ test_precision_depended<long double, float>();
+ test_precision_depended<long double, double>();
+
+ test_engine_calls<float>();
+ test_engine_calls<double>();
+ test_engine_calls<long double>();
return 0;
}
diff --git
a/libstdc++-v3/testsuite/26_numerics/random/piecewise_linear_distribution/operators/serialize2.cc
b/libstdc++-v3/testsuite/26_numerics/random/piecewise_linear_distribution/operators/serialize2.cc
index 21365057f9e..55f0d8c427d 100644
---
a/libstdc++-v3/testsuite/26_numerics/random/piecewise_linear_distribution/operators/serialize2.cc
+++
b/libstdc++-v3/testsuite/26_numerics/random/piecewise_linear_distribution/operators/serialize2.cc
@@ -24,7 +24,7 @@ test_default()
if (!std::numeric_limits<RealType>::is_iec559)
return;
-
+
char const* expected = nullptr;
switch (std::numeric_limits<RealType>::digits)
{
@@ -40,7 +40,7 @@ test_default()
" 1.00000000000000000e+00 1.00000000000000000e+00";
VERIFY( res == expected );
break;
- case 64: // ieee80
+ case 64: // ieee80
expected =
"1 0.000000000000000000000e+00 1.000000000000000000000e+00"
" 1.000000000000000000000e+00 1.000000000000000000000e+00";
@@ -63,7 +63,7 @@ test_custom()
str << u;
std::string res = str.str();
- std::piecewise_constant_distribution<RealType> v;
+ std::piecewise_linear_distribution<RealType> v;
str >> v;
// This does not hold currently
// VERIFY( u == v );
@@ -77,16 +77,16 @@ test_custom()
case 24: // ieee32
expected =
"3 0.000000000e+00 3.333333433e-01 6.666666865e-01 1.000000000e+00"
- " 6.666666534e-01 8.888888977e-01 1.111111142e+00 1.333333307e+00";
+ " 6.666666865e-01 8.888888955e-01 1.111111164e+00 1.333333373e+00";
VERIFY( res == expected );
break;
case 53: // ieee64
expected =
- "3 0.00000000000000000e+00 3.33333333333333315e-01
6.66666666666666630e-01 1.00000000000000000e+00"
+ "3 0.00000000000000000e+00 3.33333333333333315e-01
6.66666666666666630e-01 1.00000000000000000e+00"
" 6.66666666666666630e-01 8.88888888888888840e-01
1.11111111111111094e+00 1.33333333333333326e+00";
VERIFY( res == expected );
break;
- case 64: // ieee80
+ case 64: // ieee80
expected =
"3 0.000000000000000000000e+00 3.333333333333333333424e-01
6.666666666666666666847e-01 1.000000000000000000000e+00"
" 6.666666666666666296592e-01 8.888888888888888395456e-01
1.111111111111111160454e+00 1.333333333333333259318e+00";
@@ -103,10 +103,9 @@ int main()
test_default<double>();
test_default<long double>();
-#ifdef __x86_64__
test_custom<float>();
test_custom<double>();
-#endif
test_custom<long double>();
+
return 0;
}
--
2.54.0