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
This commit is contained in:
Edward Smith-Rowland 2019-03-06 13:38:32 +00:00 committed by Edward Smith-Rowland
parent 669a6fdcb4
commit f29a1ef2d8
6 changed files with 247 additions and 19 deletions

View File

@ -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 <ville.voutilainen@gmail.com>
Rewrite variant.

View File

@ -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);

View File

@ -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
// <http://www.gnu.org/licenses/>.
#include <initializer_list>
#include <cmath>
#if defined(__TEST_DEBUG)
# include <iostream>
# define VERIFY(A) \
if (!(A)) \
{ \
std::cout << "line " << __LINE__ \
<< " std::assoc_legendre(l, m, x) == 0: " << (A) \
<< '\n'; \
}
#else
# include <testsuite_hooks.h>
#endif
template<typename _Tp>
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<float>();
test_m_gt_l<double>();
test_m_gt_l<long double>();
}

View File

@ -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
// <http://www.gnu.org/licenses/>.
#include <initializer_list>
#include <cmath>
#if defined(__TEST_DEBUG)
# include <iostream>
# define VERIFY(A) \
if (!(A)) \
{ \
std::cout << "line " << __LINE__ \
<< " std::sph_legendre(l, m, x) == 0: " << (A) \
<< '\n'; \
}
#else
# include <testsuite_hooks.h>
#endif
template<typename _Tp>
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<float>();
test_m_gt_l<double>();
test_m_gt_l<long double>();
}

View File

@ -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
// <http://www.gnu.org/licenses/>.
#include <tr1/cmath>
#if defined(__TEST_DEBUG)
# include <iostream>
# define VERIFY(A) \
if (!(A)) \
{ \
std::cout << "line " << __LINE__ \
<< " std::tr1::assoc_legendre(l, m, x) == 0: " << (A) \
<< '\n'; \
}
#else
# include <testsuite_hooks.h>
#endif
template<typename _Tp>
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<float>();
test_m_gt_l<double>();
test_m_gt_l<long double>();
}

View File

@ -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
// <http://www.gnu.org/licenses/>.
#include <tr1/cmath>
#if defined(__TEST_DEBUG)
# include <iostream>
# define VERIFY(A) \
if (!(A)) \
{ \
std::cout << "line " << __LINE__ \
<< " std::sph_legendre(l, m, x) == 0: " << (A) \
<< '\n'; \
}
#else
# include <testsuite_hooks.h>
#endif
template<typename _Tp>
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<float>();
test_m_gt_l<double>();
test_m_gt_l<long double>();
}