From f29a1ef2d8efb9423b878c9d5da1961527fce707 Mon Sep 17 00:00:00 2001 From: Edward Smith-Rowland <3dw4rd@verizon.net> Date: Wed, 6 Mar 2019 13:38:32 +0000 Subject: [PATCH] PR libstdc++/86655 - std::assoc_legendre should not constrain 2019-03-06 Edward Smith-Rowland <3dw4rd@verizon.net> PR libstdc++/86655 - std::assoc_legendre should not constrain the value of m (or x). * include/tr1/legendre_function.tcc (__assoc_legendre_p, __sph_legendre): If degree > order Don't throw, return 0. (__legendre_p, __assoc_legendre_p): Don't constrain x either. * testsuite/special_functions/02_assoc_legendre/pr86655.cc: New test. * testsuite/special_functions/20_sph_legendre/pr86655.cc: New test. * testsuite/tr1/5_numerical_facilities/special_functions/ 02_assoc_legendre/pr86655.cc: New test. * testsuite/tr1/5_numerical_facilities/special_functions/ 22_sph_legendre/pr86655.cc: New test. From-SVN: r269423 --- libstdc++-v3/ChangeLog | 14 +++++ .../include/tr1/legendre_function.tcc | 28 +++------- .../02_assoc_legendre/pr86655.cc | 56 +++++++++++++++++++ .../20_sph_legendre/pr86655.cc | 56 +++++++++++++++++++ .../02_assoc_legendre/pr86655.cc | 56 +++++++++++++++++++ .../22_sph_legendre/pr86655.cc | 56 +++++++++++++++++++ 6 files changed, 247 insertions(+), 19 deletions(-) create mode 100644 libstdc++-v3/testsuite/special_functions/02_assoc_legendre/pr86655.cc create mode 100644 libstdc++-v3/testsuite/special_functions/20_sph_legendre/pr86655.cc create mode 100644 libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/pr86655.cc create mode 100644 libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/pr86655.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 7a199f8fc19..4cbdc80aa08 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,17 @@ +2019-03-06 Edward Smith-Rowland <3dw4rd@verizon.net> + + PR libstdc++/86655 - std::assoc_legendre should not constrain + the value of m (or x). + * include/tr1/legendre_function.tcc (__assoc_legendre_p, + __sph_legendre): If degree > order Don't throw, return 0. + (__legendre_p, __assoc_legendre_p): Don't constrain x either. + * testsuite/special_functions/02_assoc_legendre/pr86655.cc: New test. + * testsuite/special_functions/20_sph_legendre/pr86655.cc: New test. + * testsuite/tr1/5_numerical_facilities/special_functions/ + 02_assoc_legendre/pr86655.cc: New test. + * testsuite/tr1/5_numerical_facilities/special_functions/ + 22_sph_legendre/pr86655.cc: New test. + 2019-03-06 Ville Voutilainen Rewrite variant. diff --git a/libstdc++-v3/include/tr1/legendre_function.tcc b/libstdc++-v3/include/tr1/legendre_function.tcc index 33d933a1238..f782907a67d 100644 --- a/libstdc++-v3/include/tr1/legendre_function.tcc +++ b/libstdc++-v3/include/tr1/legendre_function.tcc @@ -82,10 +82,7 @@ namespace tr1 __poly_legendre_p(unsigned int __l, _Tp __x) { - if ((__x < _Tp(-1)) || (__x > _Tp(+1))) - std::__throw_domain_error(__N("Argument out of range" - " in __poly_legendre_p.")); - else if (__isnan(__x)) + if (__isnan(__x)) return std::numeric_limits<_Tp>::quiet_NaN(); else if (__x == +_Tp(1)) return +_Tp(1); @@ -126,11 +123,11 @@ namespace tr1 * @f[ * P_l^m(x) = (1 - x^2)^{m/2}\frac{d^m}{dx^m}P_l(x) * @f] + * @note @f$ P_l^m(x) = 0 @f$ if @f$ m > l @f$. * * @param l The degree of the associated Legendre function. * @f$ l >= 0 @f$. * @param m The order of the associated Legendre function. - * @f$ m <= l @f$. * @param x The argument of the associated Legendre function. * @f$ |x| <= 1 @f$. * @param phase The phase of the associated Legendre function. @@ -142,12 +139,8 @@ namespace tr1 _Tp __phase = _Tp(+1)) { - if (__x < _Tp(-1) || __x > _Tp(+1)) - std::__throw_domain_error(__N("Argument out of range" - " in __assoc_legendre_p.")); - else if (__m > __l) - std::__throw_domain_error(__N("Degree out of range" - " in __assoc_legendre_p.")); + if (__m > __l) + return _Tp(0); else if (__isnan(__x)) return std::numeric_limits<_Tp>::quiet_NaN(); else if (__m == 0) @@ -209,12 +202,12 @@ namespace tr1 * and so this function is stable for larger differences of @f$ l @f$ * and @f$ m @f$. * @note Unlike the case for __assoc_legendre_p the Condon-Shortley - * phase factor @f$ (-1)^m @f$ is present here. + * phase factor @f$ (-1)^m @f$ is present here. + * @note @f$ Y_l^m(\theta) = 0 @f$ if @f$ m > l @f$. * * @param l The degree of the spherical associated Legendre function. * @f$ l >= 0 @f$. * @param m The order of the spherical associated Legendre function. - * @f$ m <= l @f$. * @param theta The radian angle argument of the spherical associated * Legendre function. */ @@ -227,11 +220,8 @@ namespace tr1 const _Tp __x = std::cos(__theta); - if (__l < __m) - { - std::__throw_domain_error(__N("Bad argument " - "in __sph_legendre.")); - } + if (__m > __l) + return _Tp(0); else if (__m == 0) { _Tp __P = __poly_legendre_p(__l, __x); @@ -284,7 +274,7 @@ namespace tr1 _Tp __y_lm = _Tp(0); // Compute Y_l^m, l > m+1, upward recursion on l. - for (unsigned int __ll = __m + 2; __ll <= __l; ++__ll) + for (int __ll = __m + 2; __ll <= __l; ++__ll) { const _Tp __rat1 = _Tp(__ll - __m) / _Tp(__ll + __m); const _Tp __rat2 = _Tp(__ll - __m - 1) / _Tp(__ll + __m - 1); diff --git a/libstdc++-v3/testsuite/special_functions/02_assoc_legendre/pr86655.cc b/libstdc++-v3/testsuite/special_functions/02_assoc_legendre/pr86655.cc new file mode 100644 index 00000000000..2b028348ba7 --- /dev/null +++ b/libstdc++-v3/testsuite/special_functions/02_assoc_legendre/pr86655.cc @@ -0,0 +1,56 @@ +// { dg-do run { target c++11 } } +// { dg-options "-D__STDCPP_WANT_MATH_SPEC_FUNCS__ -ffp-contract=off" } + +// Copyright (C) 2019 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 +// . + +#include +#include +#if defined(__TEST_DEBUG) +# include +# define VERIFY(A) \ + if (!(A)) \ + { \ + std::cout << "line " << __LINE__ \ + << " std::assoc_legendre(l, m, x) == 0: " << (A) \ + << '\n'; \ + } +#else +# include +#endif + +template + void + test_m_gt_l() + { + bool test __attribute__((unused)) = true; + for (auto l : {0u, 1u, 2u, 5u}) + for (auto m : {l + 1u, l + 2u}) + for (auto i : {-2, -1, 0, 1, 2}) + { + auto x = _Tp(i * 0.5L); + VERIFY(std::assoc_legendre(l, m, x) == _Tp(0)); + } + } + +int +main() +{ + test_m_gt_l(); + test_m_gt_l(); + test_m_gt_l(); +} diff --git a/libstdc++-v3/testsuite/special_functions/20_sph_legendre/pr86655.cc b/libstdc++-v3/testsuite/special_functions/20_sph_legendre/pr86655.cc new file mode 100644 index 00000000000..94ee0d6ce6c --- /dev/null +++ b/libstdc++-v3/testsuite/special_functions/20_sph_legendre/pr86655.cc @@ -0,0 +1,56 @@ +// { dg-do run { target c++11 } } +// { dg-options "-D__STDCPP_WANT_MATH_SPEC_FUNCS__ -ffp-contract=off" } + +// Copyright (C) 2019 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 +// . + +#include +#include +#if defined(__TEST_DEBUG) +# include +# define VERIFY(A) \ + if (!(A)) \ + { \ + std::cout << "line " << __LINE__ \ + << " std::sph_legendre(l, m, x) == 0: " << (A) \ + << '\n'; \ + } +#else +# include +#endif + +template + void + test_m_gt_l() + { + bool test __attribute__((unused)) = true; + for (auto l : {0u, 1u, 2u, 5u}) + for (auto m : {l + 1u, l + 2u}) + for (auto i : {-2, -1, 0, 1, 2}) + { + auto theta = std::acos(_Tp(i * 0.5L)); + VERIFY(std::sph_legendre(l, m, theta) == _Tp(0)); + } + } + +int +main() +{ + test_m_gt_l(); + test_m_gt_l(); + test_m_gt_l(); +} diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/pr86655.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/pr86655.cc new file mode 100644 index 00000000000..092afddbba5 --- /dev/null +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/pr86655.cc @@ -0,0 +1,56 @@ +// { dg-do run } +// { dg-options "-std=c++98 -ffp-contract=off" } + +// Copyright (C) 2019 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 +// . + +#include +#if defined(__TEST_DEBUG) +# include +# define VERIFY(A) \ + if (!(A)) \ + { \ + std::cout << "line " << __LINE__ \ + << " std::tr1::assoc_legendre(l, m, x) == 0: " << (A) \ + << '\n'; \ + } +#else +# include +#endif + +template + void + test_m_gt_l() + { + bool test __attribute__((unused)) = true; + unsigned int larr[4] = {0u, 1u, 2u, 5u}; + for (unsigned int l = 0; l < 4; ++l) + for (unsigned int m = larr[l] + 1u; m <= larr[l] + 2u; ++m) + for (int i = -2; i <= +2; ++i) + { + _Tp x = _Tp(i * 0.5L); + VERIFY(std::tr1::assoc_legendre(larr[l], m, x) == _Tp(0)); + } + } + +int +main() +{ + test_m_gt_l(); + test_m_gt_l(); + test_m_gt_l(); +} diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/pr86655.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/pr86655.cc new file mode 100644 index 00000000000..510044378ad --- /dev/null +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/pr86655.cc @@ -0,0 +1,56 @@ +// { dg-do run } +// { dg-options "-std=c++98 -ffp-contract=off" } + +// Copyright (C) 2019 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 +// . + +#include +#if defined(__TEST_DEBUG) +# include +# define VERIFY(A) \ + if (!(A)) \ + { \ + std::cout << "line " << __LINE__ \ + << " std::sph_legendre(l, m, x) == 0: " << (A) \ + << '\n'; \ + } +#else +# include +#endif + +template + void + test_m_gt_l() + { + bool test __attribute__((unused)) = true; + unsigned int larr[4] = {0u, 1u, 2u, 5u}; + for (unsigned int l = 0; l < 4; ++l) + for (unsigned int m = larr[l] + 1u; m <= larr[l] + 2u; ++m) + for (int i = -2; i <= +2; ++i) + { + _Tp theta = std::acos(_Tp(i * 0.5L)); + VERIFY(std::tr1::sph_legendre(larr[l], m, theta) == _Tp(0)); + } + } + +int +main() +{ + test_m_gt_l(); + test_m_gt_l(); + test_m_gt_l(); +} -- 2.30.2