The piecewise distributions previously always generated a 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 float it used, however
due the ABI compatibility, 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 behaviour 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 reverts r17-2391-geae19
and r17-2392-g86a93). This is achieved by converting the values to _CalcType
that is either defined as double or _RealType. This change is not applied
to interval delta (_M_int[__k + 1] - _M_int[__k]) that used _RealType
already, to preserve the result of computations involving it.
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::_CalcType)
(piecewise_linear_distribution::_CalcType): 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 _CalcType.
* 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 _CalcType.
(piecewise_constant_distribution::param_type::param_type)
(piecewise_constant_distribution::param_type::param_type):
Cast the inputs to the _CalcType. Use _RealTyp e as input
weight functor.
(piecewise_constant_distribution::__generate_one)
(piecewise_linear_distribution::__generate_one): Extract
from operator() and use _CalcType.
(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.
Reviewed-by: Jonathan Wakely <[email protected]>
Signed-off-by: Tomasz Kamiński <[email protected]>
---
v2:
- renames _CompType to _CalcType,
- cast the literals to _CalcType, keepign the calculations in it
- apply fixup to commit description suggested on review,
and add a sentece regarding interval delta not being
changed to _CalcType: we also do not cast (_M_int[__k + 1] - _M_int[__k])
in constant distribution for same reason,
- some trailing whitespace fixes
Testing on x86_64-linux. *piecewise* test passed in all standard
modes, debug and -m32. OK for trunk?
.../doc/html/manual/using_macros.html | 3 +-
libstdc++-v3/doc/xml/manual/using.xml | 4 +-
libstdc++-v3/include/bits/random.h | 24 ++-
libstdc++-v3/include/bits/random.tcc | 203 +++++++++++-------
.../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, 521 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 2e5f4b2e1a1..0df3a2d3451 100644
--- a/libstdc++-v3/doc/html/manual/using_macros.html
+++ b/libstdc++-v3/doc/html/manual/using_macros.html
@@ -164,7 +164,8 @@
is restored to their 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">
+ 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.
diff --git a/libstdc++-v3/doc/xml/manual/using.xml
b/libstdc++-v3/doc/xml/manual/using.xml
index 027b26b72cf..da710be408f 100644
--- a/libstdc++-v3/doc/xml/manual/using.xml
+++ b/libstdc++-v3/doc/xml/manual/using.xml
@@ -1391,7 +1391,9 @@ 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.
</para>
diff --git a/libstdc++-v3/include/bits/random.h
b/libstdc++-v3/include/bits/random.h
index c219930cc29..b01b92862cc 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 _CalcType = double;
+#else
+ using _CalcType = _RealType;
+#endif
public:
/** The type of the range of the distribution. */
@@ -6552,7 +6557,7 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
_M_configure();
void
- _M_initialize2(const _RealType* __ints, _RealType __den);
+ _M_initialize2(const _RealType* __ints, _CalcType __den);
std::vector<_RealType> _M_int;
std::vector<_StorageType> _M_den;
@@ -6733,6 +6738,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
@@ -6775,6 +6785,11 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
using _StorageType
= __detail::__piecewise_distributions_storage_t<_RealType>;
+#ifdef _GLIBCXX_USE_OLD_PIECEWISE_DISTRIBUTIONS
+ using _CalcType = double;
+#else
+ using _CalcType = _RealType;
+#endif
public:
/** The type of the range of the distribution. */
@@ -6857,7 +6872,7 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
_M_configure();
void
- _M_initialize2(const _RealType* __ints, const _RealType* __dens);
+ _M_initialize2(const _RealType* __ints, const _CalcType* __dens);
std::vector<_RealType> _M_int;
std::vector<_StorageType> _M_den;
@@ -7040,6 +7055,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..aa176db4778 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 _CalcType __sum = std::accumulate(_M_den.begin(), _M_den.end(),
+ _CalcType(0));
__glibcxx_assert(__sum > 0);
__detail::__normalize(_M_den.begin(), _M_den.end(), _M_den.begin(),
__sum);
+ _CalcType __psum(0);
_M_cp.reserve(_M_den.size());
- std::partial_sum(_M_den.begin(), _M_den.end(),
- std::back_inserter(_M_cp));
+ for (_CalcType __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] = _CalcType(1);
for (size_t __k = 0; __k < _M_den.size(); ++__k)
- _M_den[__k] /= _M_int[__k + 1] - _M_int[__k];
+ _M_den[__k] = _CalcType(_CalcType(_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, _CalcType __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(_CalcType(*__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]));
+ _CalcType __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(__v + _RealType(0.5) * __delta));
+#endif
+ };
+
if (__n == 1)
{
_RealType __ints[2] = { __xmin, __xmin + __delta };
- _RealType __den = __fw(__xmin + 0.5 * __delta);
+ _CalcType __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 _CalcType __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 _CalcType __pref = __i > 0 ? __param._M_cp[__i - 1] :
_CalcType(0);
+ return __param._M_int[__i] + (__p - __pref) /
_CalcType(__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, _CalcType>
__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();
-
- const double __pref = __i > 0 ? __param._M_cp[__i - 1] : 0.0;
+ return __aurng();
- 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, _CalcType>
__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,34 +3248,37 @@ namespace __detail
piecewise_linear_distribution<_RealType>::param_type::
_M_configure()
{
- double __sum = 0.0;
+ _CalcType __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 += _CalcType(0.5)
+ * (_CalcType(_M_den[__k + 1]) + _CalcType(_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(
+ (_CalcType(_M_den[__k + 1]) - _CalcType(_M_den[__k])) / __delta);
}
__glibcxx_assert(__sum > 0);
// Now normalize the densities...
__detail::__normalize(_M_den.begin(), _M_den.end(), _M_den.begin(),
__sum);
- // ... and partial sums...
+ // ... and partial sums...
__detail::__normalize(_M_cp.begin(), _M_cp.end(), _M_cp.begin(), __sum);
// ... and slopes.
__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] = _CalcType(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 _CalcType* __dens)
{
if (__ints[0] == _RealType(0)
&& __ints[1] == _RealType(1)
@@ -3288,7 +3309,7 @@ namespace __detail
if (__bbegin == __bend)
{
- _RealType __dens[2];
+ _CalcType __dens[2];
__dens[0] = *__wbegin;
++__wbegin;
__dens[1] = *__wbegin;
@@ -3314,9 +3335,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(_CalcType(*__wbegin));
_M_configure();
}
@@ -3333,7 +3356,7 @@ namespace __detail
if (__bl.size() == 2)
{
const _RealType *__ints = __bl.begin();
- _RealType __den[2];
+ _CalcType __den[2];
__den[0] = __fw(__ints[0]);
__den[1] = __fw(__ints[1]);
_M_initialize2(__ints, __den);
@@ -3343,7 +3366,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(_CalcType(__fw(__b)));
_M_configure();
}
@@ -3356,18 +3379,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];
+ _CalcType __dens[2];
__dens[0] = __cfw(__ints[0]);
__dens[1] = __cfw(__ints[1]);
_M_initialize2(__ints, __dens);
@@ -3386,39 +3411,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 _CalcType __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 _CalcType __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 _CalcType __a = _CalcType(0.5) * __param._M_m[__i];
+ const _CalcType __b = __param._M_den[__i];
+ const _CalcType __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;
- __x += 0.5 * (std::sqrt(__d) - __b) / __a;
- }
+ const _CalcType __d = __b * __b + 4.0 * __a * __cm;
+ __x += _CalcType(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, _CalcType>
+ __aurng(__urng);
+
+ if (__param._M_cp.empty())
+ return __aurng();
+
+ return __generate_one(__aurng, __param);
}
template<typename _RealType>
@@ -3431,9 +3466,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, _CalcType>
+ __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.55.0