From 434a8652bcfca85cc7943f40edcb446d3836df0e Mon Sep 17 00:00:00 2001 From: drepper Date: Sat, 9 Aug 2014 17:56:57 +0000 Subject: * include/ext/random.tcc (uniform_on_sphere_helper): Define. (uniform_on_sphere_distribution::operator()): Use the new helper class for the implementation. * testsuite/ext/random/uniform_on_sphere_distribution/operators/ equal.cc: Remove bogus part of comment. * testsuite/ext/random/uniform_on_sphere_distribution/operators/ inequal.cc: Likewise. * testsuite/ext/random/uniform_on_sphere_distribution/operators/ serialize.cc: Add check to verify result of serialzation and deserialization. * testsuite/ext/random/uniform_on_sphere_distribution/operators/ generate.cc: New file. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@213779 138bc75d-0d04-0410-961f-82ee72b054a4 --- libstdc++-v3/include/ext/random.tcc | 91 ++++++++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 12 deletions(-) (limited to 'libstdc++-v3/include') diff --git a/libstdc++-v3/include/ext/random.tcc b/libstdc++-v3/include/ext/random.tcc index 05361d8f491..997c204ffe2 100644 --- a/libstdc++-v3/include/ext/random.tcc +++ b/libstdc++-v3/include/ext/random.tcc @@ -1540,6 +1540,83 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } + namespace { + + // Helper class for the uniform_on_sphere_distribution generation + // function. + template + class uniform_on_sphere_helper + { + typedef typename uniform_on_sphere_distribution<_Dimen, _RealType>::result_type result_type; + + public: + template + result_type operator()(_NormalDistribution& __nd, + _UniformRandomNumberGenerator& __urng) + { + result_type __ret; + typename result_type::value_type __norm; + + do + { + auto __sum = _RealType(0); + + std::generate(__ret.begin(), __ret.end(), + [&__nd, &__urng, &__sum](){ + _RealType __t = __nd(__urng); + __sum += __t * __t; + return __t; }); + __norm = std::sqrt(__sum); + } + while (__norm == _RealType(0) || ! std::isfinite(__norm)); + + std::transform(__ret.begin(), __ret.end(), __ret.begin(), + [__norm](_RealType __val){ return __val / __norm; }); + + return __ret; + } + }; + + + template + class uniform_on_sphere_helper<2, _RealType> + { + typedef typename uniform_on_sphere_distribution<2, _RealType>:: + result_type result_type; + + public: + template + result_type operator()(_NormalDistribution&, + _UniformRandomNumberGenerator& __urng) + { + result_type __ret; + _RealType __sq; + std::__detail::_Adaptor<_UniformRandomNumberGenerator, + _RealType> __aurng(__urng); + + do + { + __ret[0] = _RealType(2) * __aurng() - _RealType(1); + __ret[1] = _RealType(2) * __aurng() - _RealType(1); + + __sq = __ret[0] * __ret[0] + __ret[1] * __ret[1]; + } + while (__sq == _RealType(0) || __sq > _RealType(1)); + + // Yes, we do not just use sqrt(__sq) because hypot() is more + // accurate. + auto __norm = std::hypot(__ret[0], __ret[1]); + __ret[0] /= __norm; + __ret[1] /= __norm; + + return __ret; + } + }; + + } + + template template typename uniform_on_sphere_distribution<_Dimen, _RealType>::result_type @@ -1547,18 +1624,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator()(_UniformRandomNumberGenerator& __urng, const param_type& __p) { - result_type __ret; - _RealType __sum = _RealType(0); - - std::generate(__ret.begin(), __ret.end(), - [&__urng, &__sum, this](){ _RealType __t = _M_nd(__urng); - __sum += __t * __t; - return __t; }); - auto __norm = std::sqrt(__sum); - std::transform(__ret.begin(), __ret.end(), __ret.begin(), - [__norm](_RealType __val){ return __val / __norm; }); - - return __ret; + uniform_on_sphere_helper<_Dimen, _RealType> __helper; + return __helper(_M_nd, __urng); } template -- cgit v1.2.1