https://gcc.gnu.org/g:f8c277ed801ba6310a3d6933e6fab7493f5bfcaf
commit r17-2455-gf8c277ed801ba6310a3d6933e6fab7493f5bfcaf Author: Tomasz Kamiński <[email protected]> Date: Thu Jul 9 11:17:58 2026 +0200 libstdc++: Generate result_type bits of precision in piecewise distributions. 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 _RealType 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]> Diff: --- libstdc++-v3/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(-) diff --git a/libstdc++-v3/doc/html/manual/using_macros.html b/libstdc++-v3/doc/html/manual/using_macros.html index 2e5f4b2e1a11..0df3a2d3451d 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 027b26b72cf8..da710be408f0 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 c219930cc29f..b01b92862ccd 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 bf402876eb21..aa176db4778e 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 000000000000..ebd548eb5c4f --- /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 000000000000..6fb04ef7655f --- /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 db4193847e3e..15fb68217497 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 60838d7396b6..dae9f4aaf34f 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 000000000000..3c5b717e0f2a --- /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 000000000000..48ae22b87bb3 --- /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 0a13e0fd9e21..5da22fc10113 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 21365057f9ef..55f0d8c427d4 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; }
