diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 3af97bb89ec..65134498fe7 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,19 @@ +2014-08-09 Ulrich Drepper + + * 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. + 2014-08-09 Paolo Carlini * include/ext/pod_char_traits.h (char_traits<__gnu_cxx:: 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 diff --git a/libstdc++-v3/testsuite/ext/random/uniform_on_sphere_distribution/operators/equal.cc b/libstdc++-v3/testsuite/ext/random/uniform_on_sphere_distribution/operators/equal.cc index 35a024ee9a5..f5b8d170200 100644 --- a/libstdc++-v3/testsuite/ext/random/uniform_on_sphere_distribution/operators/equal.cc +++ b/libstdc++-v3/testsuite/ext/random/uniform_on_sphere_distribution/operators/equal.cc @@ -20,7 +20,7 @@ // with this library; see the file COPYING3. If not see // . -// 26.5.8.4.5 Class template uniform_on_sphere_distribution [rand.dist.ext.uniform_on_sphere] +// Class template uniform_on_sphere_distribution [rand.dist.ext.uniform_on_sphere] #include #include diff --git a/libstdc++-v3/testsuite/ext/random/uniform_on_sphere_distribution/operators/generate.cc b/libstdc++-v3/testsuite/ext/random/uniform_on_sphere_distribution/operators/generate.cc new file mode 100644 index 00000000000..c4024443ff0 --- /dev/null +++ b/libstdc++-v3/testsuite/ext/random/uniform_on_sphere_distribution/operators/generate.cc @@ -0,0 +1,60 @@ +// { dg-options "-std=gnu++11" } +// { dg-require-cstdint "" } +// +// 2014-08-09 Ulrich Drepper +// +// Copyright (C) 2014 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// Class template uniform_on_sphere_distribution [rand.dist.ext.uniform_on_sphere] +// Concept RandomNumberDistribution [rand.concept.dist] + +#include +#include +#include + +void +test01() +{ + bool test [[gnu::unused]] = true; + std::minstd_rand0 rng; + + __gnu_cxx::uniform_on_sphere_distribution<3> u3; + + for (size_t n = 0; n < 1000; ++n) + { + auto r = u3(rng); + + VERIFY (r[0] != 0.0 || r[1] != 0.0 || r[2] != 0.0); + } + + __gnu_cxx::uniform_on_sphere_distribution<2> u2; + + for (size_t n = 0; n < 1000; ++n) + { + auto r = u2(rng); + + VERIFY (r[0] != 0.0 || r[1] != 0.0); + } +} + +int +main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/ext/random/uniform_on_sphere_distribution/operators/inequal.cc b/libstdc++-v3/testsuite/ext/random/uniform_on_sphere_distribution/operators/inequal.cc index 9f8e8c81720..26756526f86 100644 --- a/libstdc++-v3/testsuite/ext/random/uniform_on_sphere_distribution/operators/inequal.cc +++ b/libstdc++-v3/testsuite/ext/random/uniform_on_sphere_distribution/operators/inequal.cc @@ -20,7 +20,7 @@ // with this library; see the file COPYING3. If not see // . -// 26.5.8.4.5 Class template uniform_on_sphere_distribution [rand.dist.ext.uniform_on_sphere] +// Class template uniform_on_sphere_distribution [rand.dist.ext.uniform_on_sphere] #include #include diff --git a/libstdc++-v3/testsuite/ext/random/uniform_on_sphere_distribution/operators/serialize.cc b/libstdc++-v3/testsuite/ext/random/uniform_on_sphere_distribution/operators/serialize.cc index 80264ff8294..e9a758c217e 100644 --- a/libstdc++-v3/testsuite/ext/random/uniform_on_sphere_distribution/operators/serialize.cc +++ b/libstdc++-v3/testsuite/ext/random/uniform_on_sphere_distribution/operators/serialize.cc @@ -20,8 +20,8 @@ // with this library; see the file COPYING3. If not see // . -// 26.4.8.3.* Class template uniform_on_sphere_distribution [rand.dist.ext.uniform_on_sphere] -// 26.4.2.4 Concept RandomNumberDistribution [rand.concept.dist] +// Class template uniform_on_sphere_distribution [rand.dist.ext.uniform_on_sphere] +// Concept RandomNumberDistribution [rand.concept.dist] #include #include @@ -40,6 +40,8 @@ test01() str << u; str >> v; + + VERIFY( u == v ); } int