From 37880b0da32c55bf269a10973f346a3d080961b7 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:31:56 +0200 Subject: [PATCH 01/80] apply original diff from D58876 This commit was created by taking the abandoned merge request from https://reviews.llvm.org/D58876 . --- libcxx/include/experimental/__hermite | 50 +++ libcxx/include/experimental/__laguerre | 71 +++++ libcxx/include/experimental/__legendre | 123 ++++++++ libcxx/include/experimental/cmath | 103 +++++++ .../numerics/c.math/assoc_laguerre.pass.cpp | 134 ++++++++ .../numerics/c.math/assoc_legendre.pass.cpp | 203 ++++++++++++ .../numerics/c.math/hermite.pass.cpp | 290 ++++++++++++++++++ .../numerics/c.math/laguerre.pass.cpp | 119 +++++++ .../numerics/c.math/legendre.pass.cpp | 114 +++++++ 9 files changed, 1207 insertions(+) create mode 100644 libcxx/include/experimental/__hermite create mode 100644 libcxx/include/experimental/__laguerre create mode 100644 libcxx/include/experimental/__legendre create mode 100644 libcxx/include/experimental/cmath create mode 100644 libcxx/test/libcxx/experimental/numerics/c.math/assoc_laguerre.pass.cpp create mode 100644 libcxx/test/libcxx/experimental/numerics/c.math/assoc_legendre.pass.cpp create mode 100644 libcxx/test/libcxx/experimental/numerics/c.math/hermite.pass.cpp create mode 100644 libcxx/test/libcxx/experimental/numerics/c.math/laguerre.pass.cpp create mode 100644 libcxx/test/libcxx/experimental/numerics/c.math/legendre.pass.cpp diff --git a/libcxx/include/experimental/__hermite b/libcxx/include/experimental/__hermite new file mode 100644 index 0000000000000..daa89129fc8de --- /dev/null +++ b/libcxx/include/experimental/__hermite @@ -0,0 +1,50 @@ +//===------------------------ __hermite -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the internal implementations of std::hermite. +/// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_EXPERIMENTAL___HERMITE +#define _LIBCPP_EXPERIMENTAL___HERMITE + +#include +#include +#include + +/// \return the hermite polynomial \f$ H_{n}(x) \f$ +/// \note The implementation is based on the recurrence formula +/// \f[ +/// nH_{n+1}(x) = 2x H_{n}(x) - 2 n H_{n-1} +/// \f] +/// Press, William H., et al. Numerical recipes 3rd edition: The art of +/// scientific computing. Cambridge university press, 2007, p. 182. +template +_Real __libcpp_hermite_recurrence(unsigned __n, _Real __x) { + if (__n == 0u) + return _Real(1); + + _Real __t2(1); + _Real __t1 = _Real(2) * __x; + for (unsigned __i = 1; __i < __n; ++__i) { + const _Real __t0 = _Real(2) * (__x * __t1 - _Real(__i) * __t2); + __t2 = __t1; + __t1 = __t0; + } + return __t1; +} + +template _Real __libcpp_hermite(unsigned __n, _Real __x) { + if (std::isnan(__x)) + return std::numeric_limits<_Real>::quiet_NaN(); + + return __libcpp_hermite_recurrence(__n, __x); +} + +#endif // _LIBCPP_EXPERIMENTAL___HERMITE diff --git a/libcxx/include/experimental/__laguerre b/libcxx/include/experimental/__laguerre new file mode 100644 index 0000000000000..a7fc6cfbde20e --- /dev/null +++ b/libcxx/include/experimental/__laguerre @@ -0,0 +1,71 @@ +//===------------------------ __laguerre ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the internal implementations of std::laguerre +/// and std::assoc_laguerre. +/// +//===----------------------------------------------------------------------===// + + +#ifndef _LIBCPP_EXPERIMENTAL___LAGUERRE +#define _LIBCPP_EXPERIMENTAL___LAGUERRE + +#include +#include +#include +#include + +/// \return the generalized laguerre polynomial \f$ L_{n}^{(\alpha)}(x) \f$ +/// \note The implementation is based on the recurrence formula +/// \f[ +/// nL_{n}^{(\alpha)}(x) = (-x + 2n + \alpha - 1) L_{n-1}^{(\alpha)}(x) - +/// (n + \alpha - 1) L_{n-2}^{(\alpha)}(x) +/// \f] +/// Press, William H., et al. Numerical recipes 3rd edition: The art of +/// scientific computing. Cambridge university press, 2007, p. 182. +template +_Real __libcpp_generalized_laguerre_recurrence(unsigned __n, _Real __alpha, + _Real __x) { + if (__n == 0u) + return _Real(1); + + _Real __delta = __alpha - __x; + _Real __li = _Real(1) + __delta; + const _Real __alpham1 = __alpha - _Real(1); + for (unsigned __i = 2; __i <= __n; ++__i) { + __delta = (__delta * (_Real(__i) + __alpham1) - __x * __li) / _Real(__i); + __li += __delta; + } + return __li; +} + +template +_Real __libcpp_assoc_laguerre(unsigned __n, unsigned __m, _Real __x) { + if (std::isnan(__x)) + return std::numeric_limits<_Real>::quiet_NaN(); + + if (__x < _Real(0)) + _VSTD::__throw_domain_error( + "Argument of assoc_laguerre function is out of range"); + + return __libcpp_generalized_laguerre_recurrence(__n, _Real(__m), __x); +} + +template _Real __libcpp_laguerre(unsigned __n, _Real __x) { + if (std::isnan(__x)) + return std::numeric_limits<_Real>::quiet_NaN(); + + if (__x < _Real(0)) + _VSTD::__throw_domain_error( + "Argument of laguerre function is out of range"); + + return __libcpp_generalized_laguerre_recurrence(__n, _Real(0), __x); +} + +#endif // _LIBCPP_EXPERIMENTAL___LAGUERRE diff --git a/libcxx/include/experimental/__legendre b/libcxx/include/experimental/__legendre new file mode 100644 index 0000000000000..d2be9b4842226 --- /dev/null +++ b/libcxx/include/experimental/__legendre @@ -0,0 +1,123 @@ +//===------------------------ __legendre ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the internal implementations of std::legendre +/// and std::assoc_legendre. +/// +//===----------------------------------------------------------------------===// + + +#ifndef _LIBCPP_EXPERIMENTAL___LEGENDRE +#define _LIBCPP_EXPERIMENTAL___LEGENDRE + +#include +#include +#include +#include + +/// \return the Legendre polynomial \f$ P_{n}(x) \f$ +/// \note The implementation is based on the recurrence formula +/// \f[ +/// (n+1)P_{n+1}(x) = (2n+1)xP_{n}(x) - nP_{n-1}(x) +/// \f] +/// Press, William H., et al. Numerical recipes 3rd edition: The art of +/// scientific computing. Cambridge university press, 2007, p. 182. +template +_Real __libcpp_legendre_recurrence(unsigned __n, _Real __x) { + if (__n == 0u) + return _Real(1); + + _Real __t2(1); + _Real __t1 = __x; + for (unsigned __i = 1; __i < __n; ++__i) { + const _Real __k = _Real(__i); + _Real __t0 = ((_Real(2) * __k + _Real(1)) * __x * __t1 - __k * __t2) / + (__k + _Real(1)); + __t2 = __t1; + __t1 = __t0; + } + return __t1; +} + +template _Real __libcpp_legendre(unsigned __n, _Real __x) { + if (std::isnan(__x)) + return std::numeric_limits<_Real>::quiet_NaN(); + + if (std::abs(__x) > _Real(1)) + _VSTD::__throw_domain_error( + "Argument of legendre function is out of range"); + + return __libcpp_legendre_recurrence(__n, __x); +} + +/// \return \f$ s^{-m} P_{l}^{m}(x) \f$ with an additonal scaling factor to +/// prevent overflow. \note The implementation is based on the recurrence +/// formula \f[ (l-m+1)P_{l+1}^{m}(x) = (2l+1)xP_{l}^{m}(x) - +/// (l+m)P_{l-1}^{m}(x) \f] with \f[ P_{m}^{m}(x) = \sqrt{1 - +/// x^2}^{m}\frac{(2m)!}{2^m m!} \f] and \f[ P_{m-1}^{m}(x) = 0 \f] \attention +/// The starting point of the recursion grows exponentially with __m! For large +/// m, we have the following relation: \f[ P_{m}^{m}(x) \approx \sqrt{1 - +/// x^2}^{m}\sqrt{2} 2^{n} \exp( n(\ln n - 1 )) \f] For example, for \f$ m = 40 +/// \f$, we already have \f$ P_{40}^{40}(0) \approx 8 \cdot 10^{58} \f$ +/// \attention The so-called Condon-Shortley phase term is omitted in the C++17 +/// standard's definition of std::assoc_laguerre. +template +_Real __libcpp_assoc_legendre_recurrence(unsigned __l, unsigned __m, _Real __x, + _Real __scale = _Real(1)) { + if (__m == 0u) + return __libcpp_legendre_recurrence(__l, __x); + + if (__l < __m) + return _Real(0); + + if (__l == 0u) + return _Real(1); + + _Real __pmm = _Real(1); + // Note: (1-x)*(1+x) is more accurate than (1-x*x) + // "What Every Computer Scientist Should Know About Floating-Point + // Arithmetic", David Goldberg, p. 38 + const _Real __t = + std::sqrt((_Real(1) - __x) * (_Real(1) + __x)) / (_Real(2) * __scale); + for (unsigned __i = 2u * __m; __i > __m; --__i) + __pmm *= __t * __i; + + if (__l == __m) + return __pmm; + + // Actually, we'd start with _pmm but it grows exponentially with __m. + // Luckily, the recursion scales. So we can start with 1 and multiply + // afterwards. + _Real __t2 = _Real(1); + _Real __t1 = _Real(2u * __m + 1u) * __x; // first iteration unfolded + for (unsigned __i = __m + 1u; __i < __l; ++__i) { + // As soon as one of the terms becomes inf, this will quickly lead to NaNs. + // float just doesn't do it for the whole range up to l==127. + const _Real __t0 = + (_Real(2u * __i + 1u) * __x * __t1 - _Real(__i + __m) * __t2) / + _Real(__i - __m + 1u); + __t2 = __t1; + __t1 = __t0; + } + return __t1 * __pmm; +} + +template +_Real __libcpp_assoc_legendre(unsigned __n, unsigned __m, _Real __x) { + if (std::isnan(__x)) + return std::numeric_limits<_Real>::quiet_NaN(); + + if (std::abs(__x) > _Real(1)) + _VSTD::__throw_domain_error( + "Argument of assoc_legendre function is out of range"); + + return __libcpp_assoc_legendre_recurrence(__n, __m, __x); +} + +#endif // _LIBCPP_EXPERIMENTAL___LEGENDRE diff --git a/libcxx/include/experimental/cmath b/libcxx/include/experimental/cmath new file mode 100644 index 0000000000000..9fd5d4fcbe190 --- /dev/null +++ b/libcxx/include/experimental/cmath @@ -0,0 +1,103 @@ +// -*- C++ -*- +//===---------------------------- cmath ----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_EXPERIMENTAL_CMATH +#define _LIBCPP_EXPERIMENTAL_CMATH + +// The following macro name shall be conditionally defined by the implementation +// to indicate conformance to the International Standard ISO/IEC JTC 1/SC 22/WG 21 N3060 +//#define __STDCPP_MATH_SPEC_FUNCS__ 201003L + +#include +#include + +#if _LIBCPP_STD_VER > 14 + +#include +#include +#include + +_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL + +inline _LIBCPP_INLINE_VISIBILITY double assoc_laguerre(unsigned __lcpp_n, unsigned __lcpp_m, double __lcpp_x) +{ + return __libcpp_assoc_laguerre(__lcpp_n , __lcpp_m, __lcpp_x); +} +inline _LIBCPP_INLINE_VISIBILITY float assoc_laguerref(unsigned __lcpp_n, unsigned __lcpp_m, float __lcpp_x) +{ + return static_cast(__libcpp_assoc_laguerre(__lcpp_n , __lcpp_m, static_cast(__lcpp_x))); +} +inline _LIBCPP_INLINE_VISIBILITY long double assoc_laguerrel(unsigned __lcpp_n, unsigned __lcpp_m, long double __lcpp_x) +{ + return __libcpp_assoc_laguerre(__lcpp_n , __lcpp_m, __lcpp_x); +} + + +inline _LIBCPP_INLINE_VISIBILITY double assoc_legendre(unsigned __lcpp_n, unsigned __lcpp_m, double __lcpp_x) +{ + return __libcpp_assoc_legendre(__lcpp_n , __lcpp_m, __lcpp_x); +} +inline _LIBCPP_INLINE_VISIBILITY float assoc_legendref(unsigned __lcpp_n, unsigned __lcpp_m, float __lcpp_x) +{ + // use double internally -- float is too prone to overflow! + return static_cast(__libcpp_assoc_legendre(__lcpp_n , __lcpp_m, static_cast(__lcpp_x))); +} +inline _LIBCPP_INLINE_VISIBILITY long double assoc_legendrel(unsigned __lcpp_n, unsigned __lcpp_m, long double __lcpp_x) +{ + return __libcpp_assoc_legendre(__lcpp_n , __lcpp_m, __lcpp_x); +} + + +inline _LIBCPP_INLINE_VISIBILITY double laguerre(unsigned __lcpp_n, double __lcpp_x) +{ + return __libcpp_laguerre(__lcpp_n ,__lcpp_x); +} +inline _LIBCPP_INLINE_VISIBILITY float laguerref(unsigned __lcpp_n, float __lcpp_x) +{ + return static_cast(__libcpp_laguerre(__lcpp_n, static_cast(__lcpp_x))); +} +inline _LIBCPP_INLINE_VISIBILITY long double laguerrel(unsigned __lcpp_n, long double __lcpp_x) +{ + return __libcpp_laguerre(__lcpp_n ,__lcpp_x); +} + + +inline _LIBCPP_INLINE_VISIBILITY double legendre(unsigned __lcpp_n, double __lcpp_x) +{ + return __libcpp_legendre(__lcpp_n ,__lcpp_x); +} +inline _LIBCPP_INLINE_VISIBILITY float legendref(unsigned __lcpp_n, float __lcpp_x) +{ + return static_cast(__libcpp_legendre(__lcpp_n, static_cast(__lcpp_x))); +} +inline _LIBCPP_INLINE_VISIBILITY long double legendrel(unsigned __lcpp_n, long double __lcpp_x) +{ + return __libcpp_legendre(__lcpp_n ,__lcpp_x); +} + +inline _LIBCPP_INLINE_VISIBILITY double hermite(unsigned __lcpp_n, double __lcpp_x) +{ + return __libcpp_hermite(__lcpp_n ,__lcpp_x); +} +inline _LIBCPP_INLINE_VISIBILITY float hermitef(unsigned __lcpp_n, float __lcpp_x) +{ + // use double internally -- float is too prone to overflow! + return static_cast(__libcpp_hermite(__lcpp_n , static_cast(__lcpp_x))); +} +inline _LIBCPP_INLINE_VISIBILITY long double hermitel(unsigned __lcpp_n, long double __lcpp_x) +{ + return __libcpp_hermite(__lcpp_n ,__lcpp_x); +} + + +_LIBCPP_END_NAMESPACE_EXPERIMENTAL + +#endif // _LIBCPP_STD_VER > 14 + +#endif // _LIBCPP_EXPERIMENTAL_CMATH diff --git a/libcxx/test/libcxx/experimental/numerics/c.math/assoc_laguerre.pass.cpp b/libcxx/test/libcxx/experimental/numerics/c.math/assoc_laguerre.pass.cpp new file mode 100644 index 0000000000000..10261f017ad70 --- /dev/null +++ b/libcxx/test/libcxx/experimental/numerics/c.math/assoc_laguerre.pass.cpp @@ -0,0 +1,134 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +#include +#include +#include + +#if _LIBCPP_STD_VER > 14 + +template void testAssocLaguerreNaNPropagation() { + const unsigned MaxN = 127; + const T x = std::numeric_limits::quiet_NaN(); + for (unsigned n = 0; n <= MaxN; ++n) { + for (unsigned m = 0; m <= MaxN; ++m) { + assert(std::isnan(std::experimental::assoc_laguerre(n, m, x))); + } + } +} + +template void testAssocLaguerreNotNaN(const T x) { + assert(!std::isnan(x)); + const unsigned MaxN = 127; + for (unsigned n = 0; n <= MaxN; ++n) { + for (unsigned m = 0; m <= MaxN; ++m) { + assert(!std::isnan(std::experimental::assoc_laguerre(n, m, x))); + } + } +} + +template void testAssocLaguerreThrows(const T x) { +#ifndef _LIBCPP_NO_EXCEPTIONS + const unsigned MaxN = 127; + for (unsigned n = 0; n <= MaxN; ++n) { + for (unsigned m = 0; m <= MaxN; ++m) { + bool Throws = false; + try { + std::experimental::assoc_laguerre(n, m, x); + } catch (const std::domain_error &) { + Throws = true; + } + assert(Throws); + } + } +#endif // _LIBCPP_NO_EXCEPTIONS +} + +template +void testAssocLaguerreVsLaguerre(const T x, const T AbsTolerance, + const T RelTolerance) { + assert(!std::isnan(x)); + const unsigned MaxN = 127; + for (unsigned n = 0; n <= MaxN; ++n) { + for (unsigned m = 0; m <= MaxN; ++m) { + const T Result = std::experimental::assoc_laguerre(n, 0, x); + const T ExpectedResult = std::experimental::laguerre(n, x); + const T Tolerance = + AbsTolerance + std::abs(ExpectedResult) * RelTolerance; + const T Difference = std::abs(Result - ExpectedResult); + assert(Difference <= Tolerance); + } + } +} + +template +void testAssocLaguerreAnalytic(const T x, const T AbsTolerance, + const T RelTolerance) { + assert(!std::isnan(x)); + const auto compareFloatingPoint = + [AbsTolerance, RelTolerance](const T Result, const T ExpectedResult) { + if (std::isinf(ExpectedResult) && std::isinf(Result)) + return true; + + if (std::isnan(ExpectedResult) || std::isnan(Result)) + return false; + + const T Tolerance = + AbsTolerance + std::abs(ExpectedResult) * RelTolerance; + return std::abs(Result - ExpectedResult) < Tolerance; + }; + + const auto l0 = [](T, unsigned) { return T(1); }; + const auto l1 = [](T x, unsigned m) { return -x + T(m + 1); }; + const auto l2 = [](T x, unsigned m) { + return x * x / T(2) - T(m + 2) * x + T(m + 1) * T(m + 2) / T(2); + }; + const auto l3 = [](T x, unsigned m) { + return -x * x * x / T(6) + T(m + 3) * x * x / T(2) - + T(m + 2) * T(m + 3) * x / T(2) + + T(m + 1) * T(m + 2) * T(m + 3) / T(6); + }; + + for (unsigned m = 0; m < 128; ++m) { + assert(compareFloatingPoint(std::experimental::assoc_laguerre(0, m, x), + l0(x, m))); + assert(compareFloatingPoint(std::experimental::assoc_laguerre(1, m, x), + l1(x, m))); + assert(compareFloatingPoint(std::experimental::assoc_laguerre(2, m, x), + l2(x, m))); + assert(compareFloatingPoint(std::experimental::assoc_laguerre(3, m, x), + l3(x, m))); + } +} + +template +void testAssocLaguerre(const T AbsTolerance, const T RelTolerance) { + testAssocLaguerreNaNPropagation(); + testAssocLaguerreThrows(T(-5)); + + const T Samples[] = {T(0.0), T(0.1), T(0.5), T(1.0), T(10.0)}; + + for (T x : Samples) { + testAssocLaguerreNotNaN(x); + testAssocLaguerreAnalytic(x, AbsTolerance, RelTolerance); + testAssocLaguerreVsLaguerre(x, AbsTolerance, RelTolerance); + } +} + +#endif + +int main(int, char **) { +#if _LIBCPP_STD_VER > 14 + testAssocLaguerre(1e-5f, 1e-5f); + testAssocLaguerre(1e-9, 1e-9); + testAssocLaguerre(1e-12, 1e-12); +#endif + return 0; +} diff --git a/libcxx/test/libcxx/experimental/numerics/c.math/assoc_legendre.pass.cpp b/libcxx/test/libcxx/experimental/numerics/c.math/assoc_legendre.pass.cpp new file mode 100644 index 0000000000000..029f8cbf3d852 --- /dev/null +++ b/libcxx/test/libcxx/experimental/numerics/c.math/assoc_legendre.pass.cpp @@ -0,0 +1,203 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +#include +#include +#include + +#if _LIBCPP_STD_VER > 14 + +template void testAssocLegendreNaNPropagation() { + const unsigned MaxN = 127; + const T x = std::numeric_limits::quiet_NaN(); + for (unsigned n = 0; n <= MaxN; ++n) { + for (unsigned m = 0; m <= MaxN; ++m) { + assert(std::isnan(std::experimental::assoc_legendre(n, m, x))); + } + } +} + +template void testAssocLegendreNotNaN(const T x) { + assert(!std::isnan(x)); + const unsigned MaxN = 127; + for (unsigned n = 0; n <= MaxN; ++n) { + for (unsigned m = 0; m <= MaxN; ++m) { + assert(!std::isnan(std::experimental::assoc_legendre(n, m, x))); + } + } +} + +template void testAssocLegendreThrows(const T x) { +#ifndef _LIBCPP_NO_EXCEPTIONS + const unsigned MaxN = 127; + for (unsigned n = 0; n <= MaxN; ++n) { + for (unsigned m = 0; m <= MaxN; ++m) { + bool Throws = false; + try { + std::experimental::assoc_legendre(n, m, x); + } catch (const std::domain_error &) { + Throws = true; + } + assert(Throws); + } + } +#endif // _LIBCPP_NO_EXCEPTIONS +} + +template +void testAssocLegendreVsLegendre(const T x, const T AbsTolerance, + const T RelTolerance) { + assert(!std::isnan(x)); + const unsigned MaxN = 127; + for (unsigned n = 0; n <= MaxN; ++n) { + for (unsigned m = 0; m <= MaxN; ++m) { + const T Result = std::experimental::assoc_legendre(n, 0, x); + const T ExpectedResult = std::experimental::legendre(n, x); + const T Tolerance = + AbsTolerance + std::abs(ExpectedResult) * RelTolerance; + const T Difference = std::abs(Result - ExpectedResult); + assert(Difference <= Tolerance); + } + } +} + +template +void testAssocLegendreAnalytic(const T x, const T AbsTolerance, + const T RelTolerance) { + assert(!std::isnan(x)); + const auto compareFloatingPoint = + [AbsTolerance, RelTolerance](const T Result, const T ExpectedResult) { + if (std::isinf(ExpectedResult) && std::isinf(Result)) + return true; + + if (std::isnan(ExpectedResult) || std::isnan(Result)) + return false; + + const T Tolerance = + AbsTolerance + std::abs(ExpectedResult) * RelTolerance; + return std::abs(Result - ExpectedResult) < Tolerance; + }; + + const auto l00 = [](T) { return T(1); }; + + const auto l10 = [](T x) { return x; }; + const auto l11 = [](T x) { return std::sqrt((T(1) - x) * (T(1) + x)); }; + + const auto l20 = [](T x) { return (T(3) * x * x - T(1)) / T(2); }; + const auto l21 = [](T x) { + return T(3) * x * std::sqrt((T(1) - x) * (T(1) + x)); + }; + const auto l22 = [](T x) { return T(3) * (T(1) - x) * (T(1) + x); }; + + const auto l30 = [](T x) { return (T(5) * x * x - T(3)) * x / T(2); }; + const auto l31 = [](T x) { + return T(3) / T(2) * (T(5) * x * x - T(1)) * + std::sqrt((T(1) - x) * (T(1) + x)); + }; + const auto l32 = [](T x) { return T(15) * x * (T(1) - x) * (T(1) + x); }; + const auto l33 = [](T x) { + const T temp = (T(1) - x) * (T(1) + x); + return T(15) * temp * std::sqrt(temp); + }; + + const auto l40 = [](T x) { + return (T(35) * x * x * x * x - T(30) * x * x + T(3)) / T(8); + }; + const auto l41 = [](T x) { + return T(5) / T(2) * x * (T(7) * x * x - T(3)) * + std::sqrt((T(1) - x) * (T(1) + x)); + }; + const auto l42 = [](T x) { + return T(15) / T(2) * (T(7) * x * x - 1) * (T(1) - x) * (T(1) + x); + }; + const auto l43 = [](T x) { + const T temp = (T(1) - x) * (T(1) + x); + return T(105) * x * temp * std::sqrt(temp); + }; + const auto l44 = [](T x) { + const T temp = (T(1) - x) * (T(1) + x); + return T(105) * temp * temp; + }; + + assert( + compareFloatingPoint(std::experimental::assoc_legendre(0, 0, x), l00(x))); + + assert( + compareFloatingPoint(std::experimental::assoc_legendre(1, 0, x), l10(x))); + assert( + compareFloatingPoint(std::experimental::assoc_legendre(1, 1, x), l11(x))); + + assert( + compareFloatingPoint(std::experimental::assoc_legendre(2, 0, x), l20(x))); + assert( + compareFloatingPoint(std::experimental::assoc_legendre(2, 1, x), l21(x))); + assert( + compareFloatingPoint(std::experimental::assoc_legendre(2, 2, x), l22(x))); + + assert( + compareFloatingPoint(std::experimental::assoc_legendre(3, 0, x), l30(x))); + assert( + compareFloatingPoint(std::experimental::assoc_legendre(3, 1, x), l31(x))); + assert( + compareFloatingPoint(std::experimental::assoc_legendre(3, 2, x), l32(x))); + assert( + compareFloatingPoint(std::experimental::assoc_legendre(3, 3, x), l33(x))); + + assert( + compareFloatingPoint(std::experimental::assoc_legendre(4, 0, x), l40(x))); + assert( + compareFloatingPoint(std::experimental::assoc_legendre(4, 1, x), l41(x))); + assert( + compareFloatingPoint(std::experimental::assoc_legendre(4, 2, x), l42(x))); + assert( + compareFloatingPoint(std::experimental::assoc_legendre(4, 3, x), l43(x))); + assert( + compareFloatingPoint(std::experimental::assoc_legendre(4, 4, x), l44(x))); + + try { + const unsigned MaxN = 127; + for (unsigned n = 0; n <= MaxN; ++n) { + for (unsigned m = n + 1; m <= MaxN; ++m) { + assert(std::experimental::assoc_legendre(n, m, x) <= AbsTolerance); + } + } + } catch (const std::domain_error &) { + // Should not throw! The expression given in + // ISO/IEC JTC 1/SC 22/WG 21 N3060 is actually well-defined for m > n! + assert(false); + } +} + +template +void testAssocLegendre(const T AbsTolerance, const T RelTolerance) { + testAssocLegendreNaNPropagation(); + testAssocLegendreThrows(T(-5)); + testAssocLegendreThrows(T(5)); + + const T Samples[] = {T(-1.0), T(-0.5), T(-0.1), T(0.0), + T(0.1), T(0.5), T(1.0)}; + + for (T x : Samples) { + testAssocLegendreNotNaN(x); + testAssocLegendreVsLegendre(x, AbsTolerance, RelTolerance); + testAssocLegendreAnalytic(x, AbsTolerance, RelTolerance); + } +} + +#endif + +int main(int, char **) { +#if _LIBCPP_STD_VER > 14 + testAssocLegendre(1e-6f, 1e-6f); + testAssocLegendre(1e-9, 1e-9); + testAssocLegendre(1e-12, 1e-12); +#endif + return 0; +} diff --git a/libcxx/test/libcxx/experimental/numerics/c.math/hermite.pass.cpp b/libcxx/test/libcxx/experimental/numerics/c.math/hermite.pass.cpp new file mode 100644 index 0000000000000..38cddf6025f61 --- /dev/null +++ b/libcxx/test/libcxx/experimental/numerics/c.math/hermite.pass.cpp @@ -0,0 +1,290 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +#include +#include +#include +#include +#include + +#if _LIBCPP_STD_VER > 14 + +template void testHermiteNaNPropagation() { + const unsigned MaxN = 127; + const T x = std::numeric_limits::quiet_NaN(); + for (unsigned n = 0; n <= MaxN; ++n) { + assert(std::isnan(std::experimental::hermite(n, x))); + } +} + +template void testHermiteNotNaN(const T x) { + assert(!std::isnan(x)); + const unsigned MaxN = 127; + for (unsigned n = 0; n <= MaxN; ++n) { + assert(!std::isnan(std::experimental::hermite(n, x))); + } +} + +template +void testHermiteAnalytic(const T x, const T AbsTolerance, + const T RelTolerance) { + assert(!std::isnan(x)); + const auto compareFloatingPoint = + [AbsTolerance, RelTolerance](const T Result, const T Expected) { + if (std::isinf(Expected) && std::isinf(Result)) + return true; + + if (std::isnan(Expected) || std::isnan(Result)) + return false; + + const T Tolerance = AbsTolerance + std::abs(Expected) * RelTolerance; + return std::abs(Result - Expected) < Tolerance; + }; + + const auto h0 = [](T) { return T(1); }; + const auto h1 = [](T x) { return T(2) * x; }; + const auto h2 = [](T x) { return T(4) * x * x - T(2); }; + const auto h3 = [](T x) { return x * (T(8) * x * x - T(12)); }; + const auto h4 = [](T x) { + return (T(16) * x * x * x * x - T(48) * x * x + T(12)); + }; + const auto h5 = [](T x) { + return x * (T(32) * x * x * x * x - T(160) * x * x + T(120)); + }; + + assert(compareFloatingPoint(std::experimental::hermite(0, x), h0(x))); + assert(compareFloatingPoint(std::experimental::hermite(1, x), h1(x))); + assert(compareFloatingPoint(std::experimental::hermite(2, x), h2(x))); + assert(compareFloatingPoint(std::experimental::hermite(3, x), h3(x))); + assert(compareFloatingPoint(std::experimental::hermite(4, x), h4(x))); + assert(compareFloatingPoint(std::experimental::hermite(5, x), h5(x))); +} + +/// \details This method checks if the following recurrence relation holds: +/// \f[ +/// H_{n+1}(x) = 2x H_{n}(x) - 2n H_{n-1}(x) +/// \f] +template +void testRecurrenceRelation(T x, T RelTolerance, T AbsTolerance) { + const unsigned MaxN = 127; + for (unsigned n = 1; n < MaxN; ++n) { + const T HermiteNext = std::experimental::hermite(n + 1, x); + const T HermiteNextRecurrence = + T(2) * x * std::experimental::hermite(n, x) - + T(2) * T(n) * std::experimental::hermite(n - 1, x); + const T Tolerance = AbsTolerance + std::abs(HermiteNext) * RelTolerance; + const T Error = std::abs(HermiteNextRecurrence - HermiteNext); + + if (std::isinf(HermiteNext)) + break; + assert(Error < Tolerance); + } +} + +template void testRecurrenceRelation(T RelTolerance, T AbsTolerance) { + const T Samples[] = {T(-1.0), T(-0.5), T(-0.1), T(0.0), + T(0.1), T(0.5), T(1.0)}; + for (T x : Samples) + testRecurrenceRelation(x, RelTolerance, AbsTolerance); +} + +/// \note Roots are taken from +/// Salzer, Herbert E., Ruth Zucker, and Ruth Capuano. +/// Table of the zeros and weight factors of the first twenty Hermite +/// polynomials. US Government Printing Office, 1952. +template std::vector getHermiteRoots(unsigned n) { + if (n == 0u) + return {}; + if (n == 1u) + return {T(0)}; + if (n == 2u) + return {T(0.707106781186548)}; + if (n == 3u) + return {T(0), + T(1.224744871391589)}; + if (n == 4u) + return {T(0.524647623275290), + T(1.650680123885785)}; + if (n == 5u) + return {T(0), T(0.958572464613819), + T(2.020182870456086)}; + if (n == 6u) + return {T(0.436077411927617), + T(1.335849074013697), + T(2.350604973674492)}; + if (n == 7u) + return {T(0), + T(0.816287882858965), + T(1.673551628767471), + T(2.651961356835233)}; + if (n == 8u) + return {T(0.381186990207322), + T(1.157193712446780), + T(1.981656756695843), + T(2.930637420257244)}; + if (n == 9u) + return {T(0), + T(0.723551018752838), + T(1.468553289216668), + T(2.266580584531843), + T(3.190993201781528)}; + if (n == 10u) + return {T(0.342901327223705), + T(1.036610829789514), + T(1.756683649299882), + T(2.532731674232790), + T(3.436159118837738)}; + if (n == 11u) + return {T(0), + T(0.65680956682100), + T(1.326557084494933), + T(2.025948015825755), + T(2.783290099781652), + T(3.668470846559583)}; + + if (n == 12u) + return {T(0.314240376254359), + T(0.947788391240164), + T(1.597682635152605), + T(2.279507080501060), + T(3.020637025120890), + T(3.889724897869782)}; + + if (n == 13u) + return {T(0), + T(0.605763879171060), + T(1.220055036590748), + T(1.853107651601512), + T(2.519735685678238), + T(3.246608978372410), + T(4.101337596178640)}; + + if (n == 14u) + return {T(0.29174551067256), + T(0.87871378732940), + T(1.47668273114114), + T(2.09518325850772), + T(2.74847072498540), + T(3.46265693360227), + T(4.30444857047363)}; + + if (n == 15u) + return {T(0.00000000000000), + T(0.56506958325558), + T(1.13611558521092), + T(1.71999257518649), + T(2.32573248617386), + T(2.96716692790560), + T(3.66995037340445), + T(4.49999070730939)}; + + if (n == 16u) + return {T(0.27348104613815), + T(0.82295144914466), + T(1.38025853919888), + T(1.95178799091625), + T(2.54620215784748), + T(3.17699916197996), + T(3.86944790486012), + T(4.68873893930582)}; + + if (n == 17u) + return {T(0), + T(0.5316330013427), + T(1.0676487257435), + T(1.6129243142212), + T(2.1735028266666), + T(2.7577629157039), + T(3.3789320911415), + T(4.0619466758755), + T(4.8713451936744)}; + if (n == 18u) + return {T(0.2582677505191), + T(0.7766829192674), + T(1.3009208583896), + T(1.8355316042616), + T(2.3862990891667), + T(2.9613775055316), + T(3.5737690684863), + T(4.2481178735681), + T(5.0483640088745)}; + if (n == 19u) + return {T(0), + T(0.5035201634239), + T(1.0103683871343), + T(1.5241706193935), + T(2.0492317098506), + T(2.5911337897945), + T(3.1578488183476), + T(3.7621873519640), + T(4.4285328066038), + T(5.2202716905375)}; + if (n == 20u) + return {T(0.2453407083009), + T(0.7374737285454), + T(1.2340762153953), + T(1.7385377121166), + T(2.2549740020893), + T(2.7888060584281), + T(3.347854567332), + T(3.9447640401156), + T(4.6036824495507), + T(5.3874808900112)}; + + return {}; +} + +/// \param [in] Tolerance of the root. This value must be smaller than +/// the smallest difference between adjacent roots in the given range +/// with n <= 20. +template void testHermiteRoots(T Tolerance) { + for (unsigned n = 0; n <= 20u; ++n) { + const auto Roots = getHermiteRoots(n); + for (T x : Roots) { + // the roots are symmetric: if x is a root, so is -x + if (x > T(0)) + assert(std::signbit(std::experimental::hermite(n, -x + Tolerance)) != + std::signbit(std::experimental::hermite(n, -x - Tolerance))); + assert(std::signbit(std::experimental::hermite(n, x + Tolerance)) != + std::signbit(std::experimental::hermite(n, x - Tolerance))); + } + } +} + +template +void testHermite(const T AbsTolerance, const T RelTolerance) { + testHermiteNaNPropagation(); + const T Samples[] = {T(-1.0), T(-0.5), T(-0.1), T(0.0), + T(0.1), T(0.5), T(1.0)}; + + for (T x : Samples) { + testHermiteNotNaN(x); + testHermiteAnalytic(x, AbsTolerance, RelTolerance); + } +} + +#endif + +int main(int, char **) { +#if _LIBCPP_STD_VER > 14 + testHermite(1e-6f, 1e-6f); + testHermite(1e-9, 1e-9); + testHermite(1e-12l, 1e-12l); + + testRecurrenceRelation(1e-6f, 1e-6f); + testRecurrenceRelation(1e-9, 1e-9); + testRecurrenceRelation(1e-12l, 1e-12l); + + testHermiteRoots(1e-6f); + testHermiteRoots(1e-9); + testHermiteRoots(1e-10l); +#endif + return 0; +} diff --git a/libcxx/test/libcxx/experimental/numerics/c.math/laguerre.pass.cpp b/libcxx/test/libcxx/experimental/numerics/c.math/laguerre.pass.cpp new file mode 100644 index 0000000000000..9856ca4838160 --- /dev/null +++ b/libcxx/test/libcxx/experimental/numerics/c.math/laguerre.pass.cpp @@ -0,0 +1,119 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +#include +#include +#include + +#if _LIBCPP_STD_VER > 14 + +template void testLaguerreNaNPropagation() { + const unsigned MaxN = 127; + const T x = std::numeric_limits::quiet_NaN(); + for (unsigned n = 0; n <= MaxN; ++n) { + assert(std::isnan(std::experimental::laguerre(n, x))); + } +} + +template void testLaguerreNotNaN(const T x) { + assert(!std::isnan(x)); + const unsigned MaxN = 127; + for (unsigned n = 0; n <= MaxN; ++n) { + assert(!std::isnan(std::experimental::laguerre(n, x))); + } +} + +template void testLaguerreThrows(const T x) { +#ifndef _LIBCPP_NO_EXCEPTIONS + const unsigned MaxN = 127; + for (unsigned n = 0; n <= MaxN; ++n) { + bool Throws = false; + try { + std::experimental::laguerre(n, x); + } catch (const std::domain_error &) { + Throws = true; + } + assert(Throws); + } +#endif // _LIBCPP_NO_EXCEPTIONS +} + +template +void testLaguerreAnalytic(const T x, const T AbsTolerance, + const T RelTolerance) { + assert(!std::isnan(x)); + const auto compareFloatingPoint = + [AbsTolerance, RelTolerance](const T Result, const T ExpectedResult) { + if (std::isinf(ExpectedResult) && std::isinf(Result)) + return true; + + if (std::isnan(ExpectedResult) || std::isnan(Result)) + return false; + + const T Tolerance = + AbsTolerance + std::abs(ExpectedResult) * RelTolerance; + return std::abs(Result - ExpectedResult) < Tolerance; + }; + + const auto l0 = [](T) { return T(1); }; + const auto l1 = [](T x) { return -x + 1; }; + const auto l2 = [](T x) { return (x * x - T(4) * x + T(2)) / T(2); }; + const auto l3 = [](T x) { + return (-x * x * x + T(9) * x * x - T(18) * x + T(6)) / T(6); + }; + const auto l4 = [](T x) { + return (x * x * x * x - T(16) * x * x * x + T(72) * x * x - T(96) * x + + T(24)) / + T(24); + }; + const auto l5 = [](T x) { + return (-x * x * x * x * x + T(25) * x * x * x * x - T(200) * x * x * x + + T(600) * x * x - T(600) * x + T(120)) / + T(120); + }; + const auto l6 = [](T x) { + return (x * x * x * x * x * x - T(36) * x * x * x * x * x + + T(450) * x * x * x * x - T(2400) * x * x * x + T(5400) * x * x - + T(4320) * x + T(720)) / + T(720); + }; + + assert(compareFloatingPoint(std::experimental::laguerre(0, x), l0(x))); + assert(compareFloatingPoint(std::experimental::laguerre(1, x), l1(x))); + assert(compareFloatingPoint(std::experimental::laguerre(2, x), l2(x))); + assert(compareFloatingPoint(std::experimental::laguerre(3, x), l3(x))); + assert(compareFloatingPoint(std::experimental::laguerre(4, x), l4(x))); + assert(compareFloatingPoint(std::experimental::laguerre(5, x), l5(x))); + assert(compareFloatingPoint(std::experimental::laguerre(6, x), l6(x))); +} + +template +void testLaguerre(const T AbsTolerance, const T RelTolerance) { + testLaguerreNaNPropagation(); + testLaguerreThrows(T(-5)); + + const T Samples[] = {T(0.0), T(0.1), T(0.5), T(1.0), T(10.0)}; + + for (T x : Samples) { + testLaguerreNotNaN(x); + testLaguerreAnalytic(x, AbsTolerance, RelTolerance); + } +} + +#endif + +int main(int, char **) { +#if _LIBCPP_STD_VER > 14 + testLaguerre(1e-6f, 1e-6f); + testLaguerre(1e-9, 1e-9); + testLaguerre(1e-12, 1e-12); +#endif + return 0; +} diff --git a/libcxx/test/libcxx/experimental/numerics/c.math/legendre.pass.cpp b/libcxx/test/libcxx/experimental/numerics/c.math/legendre.pass.cpp new file mode 100644 index 0000000000000..79a555c5bb78e --- /dev/null +++ b/libcxx/test/libcxx/experimental/numerics/c.math/legendre.pass.cpp @@ -0,0 +1,114 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +#include +#include +#include + +#if _LIBCPP_STD_VER > 14 + +template void testLegendreNaNPropagation() { + const unsigned MaxN = 127; + const T x = std::numeric_limits::quiet_NaN(); + for (unsigned n = 0; n <= MaxN; ++n) { + assert(std::isnan(std::experimental::legendre(n, x))); + } +} + +template void testLegendreNotNaN(const T x) { + assert(!std::isnan(x)); + const unsigned MaxN = 127; + for (unsigned n = 0; n <= MaxN; ++n) { + assert(!std::isnan(std::experimental::legendre(n, x))); + } +} + +template void testLegendreThrows(const T x) { +#ifndef _LIBCPP_NO_EXCEPTIONS + const unsigned MaxN = 127; + for (unsigned n = 0; n <= MaxN; ++n) { + bool Throws = false; + try { + std::experimental::legendre(n, x); + } catch (const std::domain_error &) { + Throws = true; + } + assert(Throws); + } +#endif // _LIBCPP_NO_EXCEPTIONS +} + +template +void testLegendreAnalytic(const T x, const T AbsTolerance, + const T RelTolerance) { + assert(!std::isnan(x)); + const auto compareFloatingPoint = + [AbsTolerance, RelTolerance](const T Result, const T ExpectedResult) { + if (std::isinf(ExpectedResult) && std::isinf(Result)) + return true; + + if (std::isnan(ExpectedResult) || std::isnan(Result)) + return false; + + const T Tolerance = + AbsTolerance + std::abs(ExpectedResult) * RelTolerance; + return std::abs(Result - ExpectedResult) < Tolerance; + }; + + const auto l0 = [](T) { return T(1); }; + const auto l1 = [](T x) { return x; }; + const auto l2 = [](T x) { return (T(3) * x * x - T(1)) / T(2); }; + const auto l3 = [](T x) { return (T(5) * x * x - T(3)) * x / T(2); }; + const auto l4 = [](T x) { + return (T(35) * x * x * x * x - T(30) * x * x + T(3)) / T(8); + }; + const auto l5 = [](T x) { + return (T(63) * x * x * x * x - T(70) * x * x + T(15)) * x / T(8); + }; + const auto l6 = [](T x) { + const T x2 = x * x; + return (T(231) * x2 * x2 * x2 - T(315) * x2 * x2 + T(105) * x2 - T(5)) / + T(16); + }; + + assert(compareFloatingPoint(std::experimental::legendre(0, x), l0(x))); + assert(compareFloatingPoint(std::experimental::legendre(1, x), l1(x))); + assert(compareFloatingPoint(std::experimental::legendre(2, x), l2(x))); + assert(compareFloatingPoint(std::experimental::legendre(3, x), l3(x))); + assert(compareFloatingPoint(std::experimental::legendre(4, x), l4(x))); + assert(compareFloatingPoint(std::experimental::legendre(5, x), l5(x))); + assert(compareFloatingPoint(std::experimental::legendre(6, x), l6(x))); +} + +template +void testLegendre(const T AbsTolerance, const T RelTolerance) { + testLegendreNaNPropagation(); + testLegendreThrows(T(-5)); + testLegendreThrows(T(5)); + + const T Samples[] = {T(-1.0), T(-0.5), T(-0.1), T(0.0), + T(0.1), T(0.5), T(1.0)}; + + for (T x : Samples) { + testLegendreNotNaN(x); + testLegendreAnalytic(x, AbsTolerance, RelTolerance); + } +} + +#endif + +int main(int, char **) { +#if _LIBCPP_STD_VER > 14 + testLegendre(1e-6f, 1e-6f); + testLegendre(1e-9, 1e-9); + testLegendre(1e-12, 1e-12); +#endif + return 0; +} From f73bb1b346f1b967ad78ff66bacba9636f4d8cc6 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:31:56 +0200 Subject: [PATCH 02/80] moved new files into math/ --- .../experimental/{__hermite => __math/hermite.h} | 9 +++++---- .../experimental/{__laguerre => __math/laguerre.h} | 9 +++++---- .../experimental/{__legendre => __math/legendre.h} | 9 +++++---- libcxx/include/experimental/{cmath => math} | 14 +++++++------- .../c.math => math}/assoc_laguerre.pass.cpp | 2 +- .../c.math => math}/assoc_legendre.pass.cpp | 2 +- .../{numerics/c.math => math}/hermite.pass.cpp | 2 +- .../{numerics/c.math => math}/laguerre.pass.cpp | 2 +- .../{numerics/c.math => math}/legendre.pass.cpp | 2 +- 9 files changed, 27 insertions(+), 24 deletions(-) rename libcxx/include/experimental/{__hermite => __math/hermite.h} (85%) rename libcxx/include/experimental/{__laguerre => __math/laguerre.h} (90%) rename libcxx/include/experimental/{__legendre => __math/legendre.h} (94%) rename libcxx/include/experimental/{cmath => math} (92%) rename libcxx/test/libcxx/experimental/{numerics/c.math => math}/assoc_laguerre.pass.cpp (99%) rename libcxx/test/libcxx/experimental/{numerics/c.math => math}/assoc_legendre.pass.cpp (99%) rename libcxx/test/libcxx/experimental/{numerics/c.math => math}/hermite.pass.cpp (99%) rename libcxx/test/libcxx/experimental/{numerics/c.math => math}/laguerre.pass.cpp (99%) rename libcxx/test/libcxx/experimental/{numerics/c.math => math}/legendre.pass.cpp (99%) diff --git a/libcxx/include/experimental/__hermite b/libcxx/include/experimental/__math/hermite.h similarity index 85% rename from libcxx/include/experimental/__hermite rename to libcxx/include/experimental/__math/hermite.h index daa89129fc8de..c93e05ae11303 100644 --- a/libcxx/include/experimental/__hermite +++ b/libcxx/include/experimental/__math/hermite.h @@ -1,4 +1,5 @@ -//===------------------------ __hermite -------------------------*- C++ -*-===// +// -*- C++ -*- +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -11,8 +12,8 @@ /// //===----------------------------------------------------------------------===// -#ifndef _LIBCPP_EXPERIMENTAL___HERMITE -#define _LIBCPP_EXPERIMENTAL___HERMITE +#ifndef _LIBCPP_EXPERIMENTAL___MATH_HERMITE_H +#define _LIBCPP_EXPERIMENTAL___MATH_HERMITE_H #include #include @@ -47,4 +48,4 @@ template _Real __libcpp_hermite(unsigned __n, _Real __x) { return __libcpp_hermite_recurrence(__n, __x); } -#endif // _LIBCPP_EXPERIMENTAL___HERMITE +#endif // _LIBCPP_EXPERIMENTAL___MATH_HERMITE_H diff --git a/libcxx/include/experimental/__laguerre b/libcxx/include/experimental/__math/laguerre.h similarity index 90% rename from libcxx/include/experimental/__laguerre rename to libcxx/include/experimental/__math/laguerre.h index a7fc6cfbde20e..bf1140eb75aa0 100644 --- a/libcxx/include/experimental/__laguerre +++ b/libcxx/include/experimental/__math/laguerre.h @@ -1,4 +1,5 @@ -//===------------------------ __laguerre ------------------------*- C++ -*-===// +// -*- C++ -*- +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -13,8 +14,8 @@ //===----------------------------------------------------------------------===// -#ifndef _LIBCPP_EXPERIMENTAL___LAGUERRE -#define _LIBCPP_EXPERIMENTAL___LAGUERRE +#ifndef _LIBCPP_EXPERIMENTAL___MATH_LAGUERRE_H +#define _LIBCPP_EXPERIMENTAL___MATH_LAGUERRE_H #include #include @@ -68,4 +69,4 @@ template _Real __libcpp_laguerre(unsigned __n, _Real __x) { return __libcpp_generalized_laguerre_recurrence(__n, _Real(0), __x); } -#endif // _LIBCPP_EXPERIMENTAL___LAGUERRE +#endif // _LIBCPP_EXPERIMENTAL___MATH_LAGUERRE_H diff --git a/libcxx/include/experimental/__legendre b/libcxx/include/experimental/__math/legendre.h similarity index 94% rename from libcxx/include/experimental/__legendre rename to libcxx/include/experimental/__math/legendre.h index d2be9b4842226..aa4e168853179 100644 --- a/libcxx/include/experimental/__legendre +++ b/libcxx/include/experimental/__math/legendre.h @@ -1,4 +1,5 @@ -//===------------------------ __legendre ------------------------*- C++ -*-===// +// -*- C++ -*- +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -13,8 +14,8 @@ //===----------------------------------------------------------------------===// -#ifndef _LIBCPP_EXPERIMENTAL___LEGENDRE -#define _LIBCPP_EXPERIMENTAL___LEGENDRE +#ifndef _LIBCPP_EXPERIMENTAL___MATH_LEGENDRE_H +#define _LIBCPP_EXPERIMENTAL___MATH_LEGENDRE_H #include #include @@ -120,4 +121,4 @@ _Real __libcpp_assoc_legendre(unsigned __n, unsigned __m, _Real __x) { return __libcpp_assoc_legendre_recurrence(__n, __m, __x); } -#endif // _LIBCPP_EXPERIMENTAL___LEGENDRE +#endif // _LIBCPP_EXPERIMENTAL___MATH_LEGENDRE_H diff --git a/libcxx/include/experimental/cmath b/libcxx/include/experimental/math similarity index 92% rename from libcxx/include/experimental/cmath rename to libcxx/include/experimental/math index 9fd5d4fcbe190..18289a97ae5a3 100644 --- a/libcxx/include/experimental/cmath +++ b/libcxx/include/experimental/math @@ -1,5 +1,5 @@ // -*- C++ -*- -//===---------------------------- cmath ----------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef _LIBCPP_EXPERIMENTAL_CMATH -#define _LIBCPP_EXPERIMENTAL_CMATH +#ifndef _LIBCPP_EXPERIMENTAL_MATH +#define _LIBCPP_EXPERIMENTAL_MATH // The following macro name shall be conditionally defined by the implementation // to indicate conformance to the International Standard ISO/IEC JTC 1/SC 22/WG 21 N3060 @@ -19,9 +19,9 @@ #if _LIBCPP_STD_VER > 14 -#include -#include -#include +#include +#include +#include _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL @@ -100,4 +100,4 @@ _LIBCPP_END_NAMESPACE_EXPERIMENTAL #endif // _LIBCPP_STD_VER > 14 -#endif // _LIBCPP_EXPERIMENTAL_CMATH +#endif // _LIBCPP_EXPERIMENTAL_MATH diff --git a/libcxx/test/libcxx/experimental/numerics/c.math/assoc_laguerre.pass.cpp b/libcxx/test/libcxx/experimental/math/assoc_laguerre.pass.cpp similarity index 99% rename from libcxx/test/libcxx/experimental/numerics/c.math/assoc_laguerre.pass.cpp rename to libcxx/test/libcxx/experimental/math/assoc_laguerre.pass.cpp index 10261f017ad70..945b4d531c924 100644 --- a/libcxx/test/libcxx/experimental/numerics/c.math/assoc_laguerre.pass.cpp +++ b/libcxx/test/libcxx/experimental/math/assoc_laguerre.pass.cpp @@ -9,7 +9,7 @@ // #include -#include +#include #include #if _LIBCPP_STD_VER > 14 diff --git a/libcxx/test/libcxx/experimental/numerics/c.math/assoc_legendre.pass.cpp b/libcxx/test/libcxx/experimental/math/assoc_legendre.pass.cpp similarity index 99% rename from libcxx/test/libcxx/experimental/numerics/c.math/assoc_legendre.pass.cpp rename to libcxx/test/libcxx/experimental/math/assoc_legendre.pass.cpp index 029f8cbf3d852..3de555cac6f36 100644 --- a/libcxx/test/libcxx/experimental/numerics/c.math/assoc_legendre.pass.cpp +++ b/libcxx/test/libcxx/experimental/math/assoc_legendre.pass.cpp @@ -9,7 +9,7 @@ // #include -#include +#include #include #if _LIBCPP_STD_VER > 14 diff --git a/libcxx/test/libcxx/experimental/numerics/c.math/hermite.pass.cpp b/libcxx/test/libcxx/experimental/math/hermite.pass.cpp similarity index 99% rename from libcxx/test/libcxx/experimental/numerics/c.math/hermite.pass.cpp rename to libcxx/test/libcxx/experimental/math/hermite.pass.cpp index 38cddf6025f61..e8b89b5e746e0 100644 --- a/libcxx/test/libcxx/experimental/numerics/c.math/hermite.pass.cpp +++ b/libcxx/test/libcxx/experimental/math/hermite.pass.cpp @@ -9,7 +9,7 @@ // #include -#include +#include #include #include #include diff --git a/libcxx/test/libcxx/experimental/numerics/c.math/laguerre.pass.cpp b/libcxx/test/libcxx/experimental/math/laguerre.pass.cpp similarity index 99% rename from libcxx/test/libcxx/experimental/numerics/c.math/laguerre.pass.cpp rename to libcxx/test/libcxx/experimental/math/laguerre.pass.cpp index 9856ca4838160..6c25cb83788fc 100644 --- a/libcxx/test/libcxx/experimental/numerics/c.math/laguerre.pass.cpp +++ b/libcxx/test/libcxx/experimental/math/laguerre.pass.cpp @@ -9,7 +9,7 @@ // #include -#include +#include #include #if _LIBCPP_STD_VER > 14 diff --git a/libcxx/test/libcxx/experimental/numerics/c.math/legendre.pass.cpp b/libcxx/test/libcxx/experimental/math/legendre.pass.cpp similarity index 99% rename from libcxx/test/libcxx/experimental/numerics/c.math/legendre.pass.cpp rename to libcxx/test/libcxx/experimental/math/legendre.pass.cpp index 79a555c5bb78e..35cad4bff9561 100644 --- a/libcxx/test/libcxx/experimental/numerics/c.math/legendre.pass.cpp +++ b/libcxx/test/libcxx/experimental/math/legendre.pass.cpp @@ -9,7 +9,7 @@ // #include -#include +#include #include #if _LIBCPP_STD_VER > 14 From 5d6b82440e0ac15ad684fd4a1651e2dc2d482dc3 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:31:56 +0200 Subject: [PATCH 03/80] cmake: fix include by adding new files to file listing --- libcxx/include/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 07dd25604a9c7..a3b93b4e8cf37 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -919,6 +919,9 @@ set(files execution expected experimental/__config + experimental/__math/hermite.h + experimental/__math/laguerre.h + experimental/__math/legendre.h experimental/__simd/aligned_tag.h experimental/__simd/declaration.h experimental/__simd/reference.h @@ -929,6 +932,7 @@ set(files experimental/__simd/utility.h experimental/__simd/vec_ext.h experimental/iterator + experimental/math experimental/memory experimental/propagate_const experimental/simd From b4a313a42c089e275b4ae4bef95d1f79386da80f Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:31:57 +0200 Subject: [PATCH 04/80] move test files from internal libcxx/ into std/ --- .../{libcxx => std}/experimental/math/assoc_laguerre.pass.cpp | 0 .../{libcxx => std}/experimental/math/assoc_legendre.pass.cpp | 0 libcxx/test/{libcxx => std}/experimental/math/hermite.pass.cpp | 0 libcxx/test/{libcxx => std}/experimental/math/laguerre.pass.cpp | 0 libcxx/test/{libcxx => std}/experimental/math/legendre.pass.cpp | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename libcxx/test/{libcxx => std}/experimental/math/assoc_laguerre.pass.cpp (100%) rename libcxx/test/{libcxx => std}/experimental/math/assoc_legendre.pass.cpp (100%) rename libcxx/test/{libcxx => std}/experimental/math/hermite.pass.cpp (100%) rename libcxx/test/{libcxx => std}/experimental/math/laguerre.pass.cpp (100%) rename libcxx/test/{libcxx => std}/experimental/math/legendre.pass.cpp (100%) diff --git a/libcxx/test/libcxx/experimental/math/assoc_laguerre.pass.cpp b/libcxx/test/std/experimental/math/assoc_laguerre.pass.cpp similarity index 100% rename from libcxx/test/libcxx/experimental/math/assoc_laguerre.pass.cpp rename to libcxx/test/std/experimental/math/assoc_laguerre.pass.cpp diff --git a/libcxx/test/libcxx/experimental/math/assoc_legendre.pass.cpp b/libcxx/test/std/experimental/math/assoc_legendre.pass.cpp similarity index 100% rename from libcxx/test/libcxx/experimental/math/assoc_legendre.pass.cpp rename to libcxx/test/std/experimental/math/assoc_legendre.pass.cpp diff --git a/libcxx/test/libcxx/experimental/math/hermite.pass.cpp b/libcxx/test/std/experimental/math/hermite.pass.cpp similarity index 100% rename from libcxx/test/libcxx/experimental/math/hermite.pass.cpp rename to libcxx/test/std/experimental/math/hermite.pass.cpp diff --git a/libcxx/test/libcxx/experimental/math/laguerre.pass.cpp b/libcxx/test/std/experimental/math/laguerre.pass.cpp similarity index 100% rename from libcxx/test/libcxx/experimental/math/laguerre.pass.cpp rename to libcxx/test/std/experimental/math/laguerre.pass.cpp diff --git a/libcxx/test/libcxx/experimental/math/legendre.pass.cpp b/libcxx/test/std/experimental/math/legendre.pass.cpp similarity index 100% rename from libcxx/test/libcxx/experimental/math/legendre.pass.cpp rename to libcxx/test/std/experimental/math/legendre.pass.cpp From 3871157d1a965534a5c80cf26c865a71bcc6c2e9 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:31:57 +0200 Subject: [PATCH 05/80] replace "_VSTD" by "std". similar to D117811 see https://reviews.llvm.org/D117811 --- libcxx/include/experimental/__math/laguerre.h | 4 ++-- libcxx/include/experimental/__math/legendre.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libcxx/include/experimental/__math/laguerre.h b/libcxx/include/experimental/__math/laguerre.h index bf1140eb75aa0..58b92345beb81 100644 --- a/libcxx/include/experimental/__math/laguerre.h +++ b/libcxx/include/experimental/__math/laguerre.h @@ -52,7 +52,7 @@ _Real __libcpp_assoc_laguerre(unsigned __n, unsigned __m, _Real __x) { return std::numeric_limits<_Real>::quiet_NaN(); if (__x < _Real(0)) - _VSTD::__throw_domain_error( + std::__throw_domain_error( "Argument of assoc_laguerre function is out of range"); return __libcpp_generalized_laguerre_recurrence(__n, _Real(__m), __x); @@ -63,7 +63,7 @@ template _Real __libcpp_laguerre(unsigned __n, _Real __x) { return std::numeric_limits<_Real>::quiet_NaN(); if (__x < _Real(0)) - _VSTD::__throw_domain_error( + std::__throw_domain_error( "Argument of laguerre function is out of range"); return __libcpp_generalized_laguerre_recurrence(__n, _Real(0), __x); diff --git a/libcxx/include/experimental/__math/legendre.h b/libcxx/include/experimental/__math/legendre.h index aa4e168853179..ae98e6153278b 100644 --- a/libcxx/include/experimental/__math/legendre.h +++ b/libcxx/include/experimental/__math/legendre.h @@ -51,7 +51,7 @@ template _Real __libcpp_legendre(unsigned __n, _Real __x) { return std::numeric_limits<_Real>::quiet_NaN(); if (std::abs(__x) > _Real(1)) - _VSTD::__throw_domain_error( + std::__throw_domain_error( "Argument of legendre function is out of range"); return __libcpp_legendre_recurrence(__n, __x); @@ -115,7 +115,7 @@ _Real __libcpp_assoc_legendre(unsigned __n, unsigned __m, _Real __x) { return std::numeric_limits<_Real>::quiet_NaN(); if (std::abs(__x) > _Real(1)) - _VSTD::__throw_domain_error( + std::__throw_domain_error( "Argument of assoc_legendre function is out of range"); return __libcpp_assoc_legendre_recurrence(__n, __m, __x); From 4e50b1811a92fd270111578c0bf7c84cf8c0378d Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:31:57 +0200 Subject: [PATCH 06/80] replace deprecated _LIBCPP_INLINE_VISIBILITY by _LIBCPP_HIDE_FROM_ABI --- libcxx/include/experimental/math | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/libcxx/include/experimental/math b/libcxx/include/experimental/math index 18289a97ae5a3..b2b76e913c049 100644 --- a/libcxx/include/experimental/math +++ b/libcxx/include/experimental/math @@ -25,72 +25,72 @@ _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL -inline _LIBCPP_INLINE_VISIBILITY double assoc_laguerre(unsigned __lcpp_n, unsigned __lcpp_m, double __lcpp_x) +inline _LIBCPP_HIDE_FROM_ABI double assoc_laguerre(unsigned __lcpp_n, unsigned __lcpp_m, double __lcpp_x) { return __libcpp_assoc_laguerre(__lcpp_n , __lcpp_m, __lcpp_x); } -inline _LIBCPP_INLINE_VISIBILITY float assoc_laguerref(unsigned __lcpp_n, unsigned __lcpp_m, float __lcpp_x) +inline _LIBCPP_HIDE_FROM_ABI float assoc_laguerref(unsigned __lcpp_n, unsigned __lcpp_m, float __lcpp_x) { return static_cast(__libcpp_assoc_laguerre(__lcpp_n , __lcpp_m, static_cast(__lcpp_x))); } -inline _LIBCPP_INLINE_VISIBILITY long double assoc_laguerrel(unsigned __lcpp_n, unsigned __lcpp_m, long double __lcpp_x) +inline _LIBCPP_HIDE_FROM_ABI long double assoc_laguerrel(unsigned __lcpp_n, unsigned __lcpp_m, long double __lcpp_x) { return __libcpp_assoc_laguerre(__lcpp_n , __lcpp_m, __lcpp_x); } -inline _LIBCPP_INLINE_VISIBILITY double assoc_legendre(unsigned __lcpp_n, unsigned __lcpp_m, double __lcpp_x) +inline _LIBCPP_HIDE_FROM_ABI double assoc_legendre(unsigned __lcpp_n, unsigned __lcpp_m, double __lcpp_x) { return __libcpp_assoc_legendre(__lcpp_n , __lcpp_m, __lcpp_x); } -inline _LIBCPP_INLINE_VISIBILITY float assoc_legendref(unsigned __lcpp_n, unsigned __lcpp_m, float __lcpp_x) +inline _LIBCPP_HIDE_FROM_ABI float assoc_legendref(unsigned __lcpp_n, unsigned __lcpp_m, float __lcpp_x) { // use double internally -- float is too prone to overflow! return static_cast(__libcpp_assoc_legendre(__lcpp_n , __lcpp_m, static_cast(__lcpp_x))); } -inline _LIBCPP_INLINE_VISIBILITY long double assoc_legendrel(unsigned __lcpp_n, unsigned __lcpp_m, long double __lcpp_x) +inline _LIBCPP_HIDE_FROM_ABI long double assoc_legendrel(unsigned __lcpp_n, unsigned __lcpp_m, long double __lcpp_x) { return __libcpp_assoc_legendre(__lcpp_n , __lcpp_m, __lcpp_x); } -inline _LIBCPP_INLINE_VISIBILITY double laguerre(unsigned __lcpp_n, double __lcpp_x) +inline _LIBCPP_HIDE_FROM_ABI double laguerre(unsigned __lcpp_n, double __lcpp_x) { return __libcpp_laguerre(__lcpp_n ,__lcpp_x); } -inline _LIBCPP_INLINE_VISIBILITY float laguerref(unsigned __lcpp_n, float __lcpp_x) +inline _LIBCPP_HIDE_FROM_ABI float laguerref(unsigned __lcpp_n, float __lcpp_x) { return static_cast(__libcpp_laguerre(__lcpp_n, static_cast(__lcpp_x))); } -inline _LIBCPP_INLINE_VISIBILITY long double laguerrel(unsigned __lcpp_n, long double __lcpp_x) +inline _LIBCPP_HIDE_FROM_ABI long double laguerrel(unsigned __lcpp_n, long double __lcpp_x) { return __libcpp_laguerre(__lcpp_n ,__lcpp_x); } -inline _LIBCPP_INLINE_VISIBILITY double legendre(unsigned __lcpp_n, double __lcpp_x) +inline _LIBCPP_HIDE_FROM_ABI double legendre(unsigned __lcpp_n, double __lcpp_x) { return __libcpp_legendre(__lcpp_n ,__lcpp_x); } -inline _LIBCPP_INLINE_VISIBILITY float legendref(unsigned __lcpp_n, float __lcpp_x) +inline _LIBCPP_HIDE_FROM_ABI float legendref(unsigned __lcpp_n, float __lcpp_x) { return static_cast(__libcpp_legendre(__lcpp_n, static_cast(__lcpp_x))); } -inline _LIBCPP_INLINE_VISIBILITY long double legendrel(unsigned __lcpp_n, long double __lcpp_x) +inline _LIBCPP_HIDE_FROM_ABI long double legendrel(unsigned __lcpp_n, long double __lcpp_x) { return __libcpp_legendre(__lcpp_n ,__lcpp_x); } -inline _LIBCPP_INLINE_VISIBILITY double hermite(unsigned __lcpp_n, double __lcpp_x) +inline _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __lcpp_n, double __lcpp_x) { return __libcpp_hermite(__lcpp_n ,__lcpp_x); } -inline _LIBCPP_INLINE_VISIBILITY float hermitef(unsigned __lcpp_n, float __lcpp_x) +inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __lcpp_n, float __lcpp_x) { // use double internally -- float is too prone to overflow! return static_cast(__libcpp_hermite(__lcpp_n , static_cast(__lcpp_x))); } -inline _LIBCPP_INLINE_VISIBILITY long double hermitel(unsigned __lcpp_n, long double __lcpp_x) +inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __lcpp_n, long double __lcpp_x) { return __libcpp_hermite(__lcpp_n ,__lcpp_x); } From a158fe8add8c3ec52abf393c84ffa7275139c7c4 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:31:58 +0200 Subject: [PATCH 07/80] hermite tests succeed! (fixed compiler warning: shadowing variable) --- libcxx/test/std/experimental/math/hermite.pass.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libcxx/test/std/experimental/math/hermite.pass.cpp b/libcxx/test/std/experimental/math/hermite.pass.cpp index e8b89b5e746e0..06522cdcb5d32 100644 --- a/libcxx/test/std/experimental/math/hermite.pass.cpp +++ b/libcxx/test/std/experimental/math/hermite.pass.cpp @@ -49,14 +49,14 @@ void testHermiteAnalytic(const T x, const T AbsTolerance, }; const auto h0 = [](T) { return T(1); }; - const auto h1 = [](T x) { return T(2) * x; }; - const auto h2 = [](T x) { return T(4) * x * x - T(2); }; - const auto h3 = [](T x) { return x * (T(8) * x * x - T(12)); }; - const auto h4 = [](T x) { - return (T(16) * x * x * x * x - T(48) * x * x + T(12)); + const auto h1 = [](T y) { return T(2) * y; }; + const auto h2 = [](T y) { return T(4) * y * y - T(2); }; + const auto h3 = [](T y) { return y * (T(8) * y * y - T(12)); }; + const auto h4 = [](T y) { + return (T(16) * y * y * y * y - T(48) * y * y + T(12)); }; - const auto h5 = [](T x) { - return x * (T(32) * x * x * x * x - T(160) * x * x + T(120)); + const auto h5 = [](T y) { + return y * (T(32) * y * y * y * y - T(160) * y * y + T(120)); }; assert(compareFloatingPoint(std::experimental::hermite(0, x), h0(x))); From 9938c1a7f68a2f265d6a1a3c554332d5ac55cb92 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:31:58 +0200 Subject: [PATCH 08/80] laguerre tests succeeds! (fixed compiler warning: shadowing variable) --- .../std/experimental/math/laguerre.pass.cpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/libcxx/test/std/experimental/math/laguerre.pass.cpp b/libcxx/test/std/experimental/math/laguerre.pass.cpp index 6c25cb83788fc..f6a11221e2500 100644 --- a/libcxx/test/std/experimental/math/laguerre.pass.cpp +++ b/libcxx/test/std/experimental/math/laguerre.pass.cpp @@ -63,25 +63,25 @@ void testLaguerreAnalytic(const T x, const T AbsTolerance, }; const auto l0 = [](T) { return T(1); }; - const auto l1 = [](T x) { return -x + 1; }; - const auto l2 = [](T x) { return (x * x - T(4) * x + T(2)) / T(2); }; - const auto l3 = [](T x) { - return (-x * x * x + T(9) * x * x - T(18) * x + T(6)) / T(6); + const auto l1 = [](T y) { return -y + 1; }; + const auto l2 = [](T y) { return (y * y - T(4) * y + T(2)) / T(2); }; + const auto l3 = [](T y) { + return (-y * y * y + T(9) * y * y - T(18) * y + T(6)) / T(6); }; - const auto l4 = [](T x) { - return (x * x * x * x - T(16) * x * x * x + T(72) * x * x - T(96) * x + + const auto l4 = [](T y) { + return (y * y * y * y - T(16) * y * y * y + T(72) * y * y - T(96) * y + T(24)) / T(24); }; - const auto l5 = [](T x) { - return (-x * x * x * x * x + T(25) * x * x * x * x - T(200) * x * x * x + - T(600) * x * x - T(600) * x + T(120)) / + const auto l5 = [](T y) { + return (-y * y * y * y * y + T(25) * y * y * y * y - T(200) * y * y * y + + T(600) * y * y - T(600) * y + T(120)) / T(120); }; - const auto l6 = [](T x) { - return (x * x * x * x * x * x - T(36) * x * x * x * x * x + - T(450) * x * x * x * x - T(2400) * x * x * x + T(5400) * x * x - - T(4320) * x + T(720)) / + const auto l6 = [](T y) { + return (y * y * y * y * y * y - T(36) * y * y * y * y * y + + T(450) * y * y * y * y - T(2400) * y * y * y + T(5400) * y * y - + T(4320) * y + T(720)) / T(720); }; From 87b240d048e9e1d43d4d2a3541baa568b8573e91 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:31:58 +0200 Subject: [PATCH 09/80] legendre tests succeeds! (fixed compiler warning: shadowing variable) --- .../std/experimental/math/legendre.pass.cpp | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/libcxx/test/std/experimental/math/legendre.pass.cpp b/libcxx/test/std/experimental/math/legendre.pass.cpp index 35cad4bff9561..493b1c10f345f 100644 --- a/libcxx/test/std/experimental/math/legendre.pass.cpp +++ b/libcxx/test/std/experimental/math/legendre.pass.cpp @@ -63,18 +63,18 @@ void testLegendreAnalytic(const T x, const T AbsTolerance, }; const auto l0 = [](T) { return T(1); }; - const auto l1 = [](T x) { return x; }; - const auto l2 = [](T x) { return (T(3) * x * x - T(1)) / T(2); }; - const auto l3 = [](T x) { return (T(5) * x * x - T(3)) * x / T(2); }; - const auto l4 = [](T x) { - return (T(35) * x * x * x * x - T(30) * x * x + T(3)) / T(8); + const auto l1 = [](T y) { return y; }; + const auto l2 = [](T y) { return (T(3) * y * y - T(1)) / T(2); }; + const auto l3 = [](T y) { return (T(5) * y * y - T(3)) * y / T(2); }; + const auto l4 = [](T y) { + return (T(35) * y * y * y * y - T(30) * y * y + T(3)) / T(8); }; - const auto l5 = [](T x) { - return (T(63) * x * x * x * x - T(70) * x * x + T(15)) * x / T(8); + const auto l5 = [](T y) { + return (T(63) * y * y * y * y - T(70) * y * y + T(15)) * y / T(8); }; - const auto l6 = [](T x) { - const T x2 = x * x; - return (T(231) * x2 * x2 * x2 - T(315) * x2 * x2 + T(105) * x2 - T(5)) / + const auto l6 = [](T y) { + const T y2 = y * y; + return (T(231) * y2 * y2 * y2 - T(315) * y2 * y2 + T(105) * y2 - T(5)) / T(16); }; From 6add3f4ea88a4df3da42045a53a768726f3259d9 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:31:59 +0200 Subject: [PATCH 10/80] assoc_laguerre tests succeeds! (fixed compiler warning: shadowing variable) --- .../std/experimental/math/assoc_laguerre.pass.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libcxx/test/std/experimental/math/assoc_laguerre.pass.cpp b/libcxx/test/std/experimental/math/assoc_laguerre.pass.cpp index 945b4d531c924..793a723116d48 100644 --- a/libcxx/test/std/experimental/math/assoc_laguerre.pass.cpp +++ b/libcxx/test/std/experimental/math/assoc_laguerre.pass.cpp @@ -86,13 +86,13 @@ void testAssocLaguerreAnalytic(const T x, const T AbsTolerance, }; const auto l0 = [](T, unsigned) { return T(1); }; - const auto l1 = [](T x, unsigned m) { return -x + T(m + 1); }; - const auto l2 = [](T x, unsigned m) { - return x * x / T(2) - T(m + 2) * x + T(m + 1) * T(m + 2) / T(2); + const auto l1 = [](T y, unsigned m) { return -y + T(m + 1); }; + const auto l2 = [](T y, unsigned m) { + return y * y / T(2) - T(m + 2) * y + T(m + 1) * T(m + 2) / T(2); }; - const auto l3 = [](T x, unsigned m) { - return -x * x * x / T(6) + T(m + 3) * x * x / T(2) - - T(m + 2) * T(m + 3) * x / T(2) + + const auto l3 = [](T y, unsigned m) { + return -y * y * y / T(6) + T(m + 3) * y * y / T(2) - + T(m + 2) * T(m + 3) * y / T(2) + T(m + 1) * T(m + 2) * T(m + 3) / T(6); }; From d34933d396bc8cec8789dc362729bdea614cc2ae Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:31:59 +0200 Subject: [PATCH 11/80] assoc_legendre tests succeeds! (fixed compiler warning: shadowing variable) --- .../experimental/math/assoc_legendre.pass.cpp | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/libcxx/test/std/experimental/math/assoc_legendre.pass.cpp b/libcxx/test/std/experimental/math/assoc_legendre.pass.cpp index 3de555cac6f36..ed9b1e1f9178d 100644 --- a/libcxx/test/std/experimental/math/assoc_legendre.pass.cpp +++ b/libcxx/test/std/experimental/math/assoc_legendre.pass.cpp @@ -87,42 +87,42 @@ void testAssocLegendreAnalytic(const T x, const T AbsTolerance, const auto l00 = [](T) { return T(1); }; - const auto l10 = [](T x) { return x; }; - const auto l11 = [](T x) { return std::sqrt((T(1) - x) * (T(1) + x)); }; + const auto l10 = [](T y) { return y; }; + const auto l11 = [](T y) { return std::sqrt((T(1) - y) * (T(1) + y)); }; - const auto l20 = [](T x) { return (T(3) * x * x - T(1)) / T(2); }; - const auto l21 = [](T x) { - return T(3) * x * std::sqrt((T(1) - x) * (T(1) + x)); + const auto l20 = [](T y) { return (T(3) * y * y - T(1)) / T(2); }; + const auto l21 = [](T y) { + return T(3) * y * std::sqrt((T(1) - y) * (T(1) + y)); }; - const auto l22 = [](T x) { return T(3) * (T(1) - x) * (T(1) + x); }; + const auto l22 = [](T y) { return T(3) * (T(1) - y) * (T(1) + y); }; - const auto l30 = [](T x) { return (T(5) * x * x - T(3)) * x / T(2); }; - const auto l31 = [](T x) { - return T(3) / T(2) * (T(5) * x * x - T(1)) * - std::sqrt((T(1) - x) * (T(1) + x)); + const auto l30 = [](T y) { return (T(5) * y * y - T(3)) * y / T(2); }; + const auto l31 = [](T y) { + return T(3) / T(2) * (T(5) * y * y - T(1)) * + std::sqrt((T(1) - y) * (T(1) + y)); }; - const auto l32 = [](T x) { return T(15) * x * (T(1) - x) * (T(1) + x); }; - const auto l33 = [](T x) { - const T temp = (T(1) - x) * (T(1) + x); + const auto l32 = [](T y) { return T(15) * y * (T(1) - y) * (T(1) + y); }; + const auto l33 = [](T y) { + const T temp = (T(1) - y) * (T(1) + y); return T(15) * temp * std::sqrt(temp); }; - const auto l40 = [](T x) { - return (T(35) * x * x * x * x - T(30) * x * x + T(3)) / T(8); + const auto l40 = [](T y) { + return (T(35) * y * y * y * y - T(30) * y * y + T(3)) / T(8); }; - const auto l41 = [](T x) { - return T(5) / T(2) * x * (T(7) * x * x - T(3)) * - std::sqrt((T(1) - x) * (T(1) + x)); + const auto l41 = [](T y) { + return T(5) / T(2) * y * (T(7) * y * y - T(3)) * + std::sqrt((T(1) - y) * (T(1) + y)); }; - const auto l42 = [](T x) { - return T(15) / T(2) * (T(7) * x * x - 1) * (T(1) - x) * (T(1) + x); + const auto l42 = [](T y) { + return T(15) / T(2) * (T(7) * y * y - 1) * (T(1) - y) * (T(1) + y); }; - const auto l43 = [](T x) { - const T temp = (T(1) - x) * (T(1) + x); - return T(105) * x * temp * std::sqrt(temp); + const auto l43 = [](T y) { + const T temp = (T(1) - y) * (T(1) + y); + return T(105) * y * temp * std::sqrt(temp); }; - const auto l44 = [](T x) { - const T temp = (T(1) - x) * (T(1) + x); + const auto l44 = [](T y) { + const T temp = (T(1) - y) * (T(1) + y); return T(105) * temp * temp; }; From b13a0005056d9eeb41318097de24339f35ff1187 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:31:59 +0200 Subject: [PATCH 12/80] hermite: fix documentation comment --- libcxx/include/experimental/__math/hermite.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/include/experimental/__math/hermite.h b/libcxx/include/experimental/__math/hermite.h index c93e05ae11303..ebd4555b4a49e 100644 --- a/libcxx/include/experimental/__math/hermite.h +++ b/libcxx/include/experimental/__math/hermite.h @@ -22,10 +22,10 @@ /// \return the hermite polynomial \f$ H_{n}(x) \f$ /// \note The implementation is based on the recurrence formula /// \f[ -/// nH_{n+1}(x) = 2x H_{n}(x) - 2 n H_{n-1} +/// H_{n+1}(x) = 2x H_{n}(x) - 2 n H_{n-1} /// \f] /// Press, William H., et al. Numerical recipes 3rd edition: The art of -/// scientific computing. Cambridge university press, 2007, p. 182. +/// scientific computing. Cambridge university press, 2007, p. 183. template _Real __libcpp_hermite_recurrence(unsigned __n, _Real __x) { if (__n == 0u) From 2333750256bb30f9ef507c65fab348af476540ec Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:00 +0200 Subject: [PATCH 13/80] hermite: minor code changes: rename variables, brace initialization --- libcxx/include/experimental/__math/hermite.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libcxx/include/experimental/__math/hermite.h b/libcxx/include/experimental/__math/hermite.h index ebd4555b4a49e..b89cb0b27b6d9 100644 --- a/libcxx/include/experimental/__math/hermite.h +++ b/libcxx/include/experimental/__math/hermite.h @@ -28,17 +28,17 @@ /// scientific computing. Cambridge university press, 2007, p. 183. template _Real __libcpp_hermite_recurrence(unsigned __n, _Real __x) { - if (__n == 0u) - return _Real(1); + if (0u == __n) + return _Real{1}; - _Real __t2(1); - _Real __t1 = _Real(2) * __x; + _Real __H_nPrev{1}; + _Real __H_n = _Real{2} * __x; for (unsigned __i = 1; __i < __n; ++__i) { - const _Real __t0 = _Real(2) * (__x * __t1 - _Real(__i) * __t2); - __t2 = __t1; - __t1 = __t0; + const _Real __H_nNext = _Real{2} * (__x * __H_n - _Real{__i} * __H_nPrev); + __H_nPrev = __H_n; + __H_n = __H_nNext; } - return __t1; + return __H_n; } template _Real __libcpp_hermite(unsigned __n, _Real __x) { From 188edd1c8f319ffa7a4181a8f7c32fdddb2ba770 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:00 +0200 Subject: [PATCH 14/80] create experimental/math module --- libcxx/include/module.modulemap | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 4ad506781c489..297c687fbc896 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -521,6 +521,10 @@ module std_experimental [system] { header "experimental/iterator" export * } + module math { + header "experimental/math" + export * + } module memory { header "experimental/memory" export * From 073ae40bc0176efe4b5d9eae90fd8cffa3a59c15 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:00 +0200 Subject: [PATCH 15/80] set header info for lit --- libcxx/utils/libcxx/header_information.py | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/utils/libcxx/header_information.py b/libcxx/utils/libcxx/header_information.py index 166c9a77c08e7..25fadadfb1d0a 100644 --- a/libcxx/utils/libcxx/header_information.py +++ b/libcxx/utils/libcxx/header_information.py @@ -56,6 +56,7 @@ "cwchar": "// UNSUPPORTED: no-wide-characters", "cwctype": "// UNSUPPORTED: no-wide-characters", "experimental/iterator": "// UNSUPPORTED: c++03", + "experimental/math": "// UNSUPPORTED: c++03, c++11, c++14", "experimental/propagate_const": "// UNSUPPORTED: c++03", "experimental/simd": "// UNSUPPORTED: c++03", "experimental/type_traits": "// UNSUPPORTED: c++03", From 8f4573be695e0bf2760c26a52613494875292c6f Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:01 +0200 Subject: [PATCH 16/80] keeping only hermite, i.e. remove laguerre, legendre --- libcxx/include/CMakeLists.txt | 2 - libcxx/include/experimental/__math/laguerre.h | 72 ------- libcxx/include/experimental/__math/legendre.h | 124 ----------- libcxx/include/experimental/math | 57 ----- .../experimental/math/assoc_laguerre.pass.cpp | 134 ------------ .../experimental/math/assoc_legendre.pass.cpp | 203 ------------------ .../std/experimental/math/laguerre.pass.cpp | 119 ---------- .../std/experimental/math/legendre.pass.cpp | 114 ---------- 8 files changed, 825 deletions(-) delete mode 100644 libcxx/include/experimental/__math/laguerre.h delete mode 100644 libcxx/include/experimental/__math/legendre.h delete mode 100644 libcxx/test/std/experimental/math/assoc_laguerre.pass.cpp delete mode 100644 libcxx/test/std/experimental/math/assoc_legendre.pass.cpp delete mode 100644 libcxx/test/std/experimental/math/laguerre.pass.cpp delete mode 100644 libcxx/test/std/experimental/math/legendre.pass.cpp diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index a3b93b4e8cf37..3837506bc295f 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -920,8 +920,6 @@ set(files expected experimental/__config experimental/__math/hermite.h - experimental/__math/laguerre.h - experimental/__math/legendre.h experimental/__simd/aligned_tag.h experimental/__simd/declaration.h experimental/__simd/reference.h diff --git a/libcxx/include/experimental/__math/laguerre.h b/libcxx/include/experimental/__math/laguerre.h deleted file mode 100644 index 58b92345beb81..0000000000000 --- a/libcxx/include/experimental/__math/laguerre.h +++ /dev/null @@ -1,72 +0,0 @@ -// -*- C++ -*- -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// This file contains the internal implementations of std::laguerre -/// and std::assoc_laguerre. -/// -//===----------------------------------------------------------------------===// - - -#ifndef _LIBCPP_EXPERIMENTAL___MATH_LAGUERRE_H -#define _LIBCPP_EXPERIMENTAL___MATH_LAGUERRE_H - -#include -#include -#include -#include - -/// \return the generalized laguerre polynomial \f$ L_{n}^{(\alpha)}(x) \f$ -/// \note The implementation is based on the recurrence formula -/// \f[ -/// nL_{n}^{(\alpha)}(x) = (-x + 2n + \alpha - 1) L_{n-1}^{(\alpha)}(x) - -/// (n + \alpha - 1) L_{n-2}^{(\alpha)}(x) -/// \f] -/// Press, William H., et al. Numerical recipes 3rd edition: The art of -/// scientific computing. Cambridge university press, 2007, p. 182. -template -_Real __libcpp_generalized_laguerre_recurrence(unsigned __n, _Real __alpha, - _Real __x) { - if (__n == 0u) - return _Real(1); - - _Real __delta = __alpha - __x; - _Real __li = _Real(1) + __delta; - const _Real __alpham1 = __alpha - _Real(1); - for (unsigned __i = 2; __i <= __n; ++__i) { - __delta = (__delta * (_Real(__i) + __alpham1) - __x * __li) / _Real(__i); - __li += __delta; - } - return __li; -} - -template -_Real __libcpp_assoc_laguerre(unsigned __n, unsigned __m, _Real __x) { - if (std::isnan(__x)) - return std::numeric_limits<_Real>::quiet_NaN(); - - if (__x < _Real(0)) - std::__throw_domain_error( - "Argument of assoc_laguerre function is out of range"); - - return __libcpp_generalized_laguerre_recurrence(__n, _Real(__m), __x); -} - -template _Real __libcpp_laguerre(unsigned __n, _Real __x) { - if (std::isnan(__x)) - return std::numeric_limits<_Real>::quiet_NaN(); - - if (__x < _Real(0)) - std::__throw_domain_error( - "Argument of laguerre function is out of range"); - - return __libcpp_generalized_laguerre_recurrence(__n, _Real(0), __x); -} - -#endif // _LIBCPP_EXPERIMENTAL___MATH_LAGUERRE_H diff --git a/libcxx/include/experimental/__math/legendre.h b/libcxx/include/experimental/__math/legendre.h deleted file mode 100644 index ae98e6153278b..0000000000000 --- a/libcxx/include/experimental/__math/legendre.h +++ /dev/null @@ -1,124 +0,0 @@ -// -*- C++ -*- -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// This file contains the internal implementations of std::legendre -/// and std::assoc_legendre. -/// -//===----------------------------------------------------------------------===// - - -#ifndef _LIBCPP_EXPERIMENTAL___MATH_LEGENDRE_H -#define _LIBCPP_EXPERIMENTAL___MATH_LEGENDRE_H - -#include -#include -#include -#include - -/// \return the Legendre polynomial \f$ P_{n}(x) \f$ -/// \note The implementation is based on the recurrence formula -/// \f[ -/// (n+1)P_{n+1}(x) = (2n+1)xP_{n}(x) - nP_{n-1}(x) -/// \f] -/// Press, William H., et al. Numerical recipes 3rd edition: The art of -/// scientific computing. Cambridge university press, 2007, p. 182. -template -_Real __libcpp_legendre_recurrence(unsigned __n, _Real __x) { - if (__n == 0u) - return _Real(1); - - _Real __t2(1); - _Real __t1 = __x; - for (unsigned __i = 1; __i < __n; ++__i) { - const _Real __k = _Real(__i); - _Real __t0 = ((_Real(2) * __k + _Real(1)) * __x * __t1 - __k * __t2) / - (__k + _Real(1)); - __t2 = __t1; - __t1 = __t0; - } - return __t1; -} - -template _Real __libcpp_legendre(unsigned __n, _Real __x) { - if (std::isnan(__x)) - return std::numeric_limits<_Real>::quiet_NaN(); - - if (std::abs(__x) > _Real(1)) - std::__throw_domain_error( - "Argument of legendre function is out of range"); - - return __libcpp_legendre_recurrence(__n, __x); -} - -/// \return \f$ s^{-m} P_{l}^{m}(x) \f$ with an additonal scaling factor to -/// prevent overflow. \note The implementation is based on the recurrence -/// formula \f[ (l-m+1)P_{l+1}^{m}(x) = (2l+1)xP_{l}^{m}(x) - -/// (l+m)P_{l-1}^{m}(x) \f] with \f[ P_{m}^{m}(x) = \sqrt{1 - -/// x^2}^{m}\frac{(2m)!}{2^m m!} \f] and \f[ P_{m-1}^{m}(x) = 0 \f] \attention -/// The starting point of the recursion grows exponentially with __m! For large -/// m, we have the following relation: \f[ P_{m}^{m}(x) \approx \sqrt{1 - -/// x^2}^{m}\sqrt{2} 2^{n} \exp( n(\ln n - 1 )) \f] For example, for \f$ m = 40 -/// \f$, we already have \f$ P_{40}^{40}(0) \approx 8 \cdot 10^{58} \f$ -/// \attention The so-called Condon-Shortley phase term is omitted in the C++17 -/// standard's definition of std::assoc_laguerre. -template -_Real __libcpp_assoc_legendre_recurrence(unsigned __l, unsigned __m, _Real __x, - _Real __scale = _Real(1)) { - if (__m == 0u) - return __libcpp_legendre_recurrence(__l, __x); - - if (__l < __m) - return _Real(0); - - if (__l == 0u) - return _Real(1); - - _Real __pmm = _Real(1); - // Note: (1-x)*(1+x) is more accurate than (1-x*x) - // "What Every Computer Scientist Should Know About Floating-Point - // Arithmetic", David Goldberg, p. 38 - const _Real __t = - std::sqrt((_Real(1) - __x) * (_Real(1) + __x)) / (_Real(2) * __scale); - for (unsigned __i = 2u * __m; __i > __m; --__i) - __pmm *= __t * __i; - - if (__l == __m) - return __pmm; - - // Actually, we'd start with _pmm but it grows exponentially with __m. - // Luckily, the recursion scales. So we can start with 1 and multiply - // afterwards. - _Real __t2 = _Real(1); - _Real __t1 = _Real(2u * __m + 1u) * __x; // first iteration unfolded - for (unsigned __i = __m + 1u; __i < __l; ++__i) { - // As soon as one of the terms becomes inf, this will quickly lead to NaNs. - // float just doesn't do it for the whole range up to l==127. - const _Real __t0 = - (_Real(2u * __i + 1u) * __x * __t1 - _Real(__i + __m) * __t2) / - _Real(__i - __m + 1u); - __t2 = __t1; - __t1 = __t0; - } - return __t1 * __pmm; -} - -template -_Real __libcpp_assoc_legendre(unsigned __n, unsigned __m, _Real __x) { - if (std::isnan(__x)) - return std::numeric_limits<_Real>::quiet_NaN(); - - if (std::abs(__x) > _Real(1)) - std::__throw_domain_error( - "Argument of assoc_legendre function is out of range"); - - return __libcpp_assoc_legendre_recurrence(__n, __m, __x); -} - -#endif // _LIBCPP_EXPERIMENTAL___MATH_LEGENDRE_H diff --git a/libcxx/include/experimental/math b/libcxx/include/experimental/math index b2b76e913c049..a0a4f70ad4237 100644 --- a/libcxx/include/experimental/math +++ b/libcxx/include/experimental/math @@ -20,66 +20,9 @@ #if _LIBCPP_STD_VER > 14 #include -#include -#include _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL -inline _LIBCPP_HIDE_FROM_ABI double assoc_laguerre(unsigned __lcpp_n, unsigned __lcpp_m, double __lcpp_x) -{ - return __libcpp_assoc_laguerre(__lcpp_n , __lcpp_m, __lcpp_x); -} -inline _LIBCPP_HIDE_FROM_ABI float assoc_laguerref(unsigned __lcpp_n, unsigned __lcpp_m, float __lcpp_x) -{ - return static_cast(__libcpp_assoc_laguerre(__lcpp_n , __lcpp_m, static_cast(__lcpp_x))); -} -inline _LIBCPP_HIDE_FROM_ABI long double assoc_laguerrel(unsigned __lcpp_n, unsigned __lcpp_m, long double __lcpp_x) -{ - return __libcpp_assoc_laguerre(__lcpp_n , __lcpp_m, __lcpp_x); -} - - -inline _LIBCPP_HIDE_FROM_ABI double assoc_legendre(unsigned __lcpp_n, unsigned __lcpp_m, double __lcpp_x) -{ - return __libcpp_assoc_legendre(__lcpp_n , __lcpp_m, __lcpp_x); -} -inline _LIBCPP_HIDE_FROM_ABI float assoc_legendref(unsigned __lcpp_n, unsigned __lcpp_m, float __lcpp_x) -{ - // use double internally -- float is too prone to overflow! - return static_cast(__libcpp_assoc_legendre(__lcpp_n , __lcpp_m, static_cast(__lcpp_x))); -} -inline _LIBCPP_HIDE_FROM_ABI long double assoc_legendrel(unsigned __lcpp_n, unsigned __lcpp_m, long double __lcpp_x) -{ - return __libcpp_assoc_legendre(__lcpp_n , __lcpp_m, __lcpp_x); -} - - -inline _LIBCPP_HIDE_FROM_ABI double laguerre(unsigned __lcpp_n, double __lcpp_x) -{ - return __libcpp_laguerre(__lcpp_n ,__lcpp_x); -} -inline _LIBCPP_HIDE_FROM_ABI float laguerref(unsigned __lcpp_n, float __lcpp_x) -{ - return static_cast(__libcpp_laguerre(__lcpp_n, static_cast(__lcpp_x))); -} -inline _LIBCPP_HIDE_FROM_ABI long double laguerrel(unsigned __lcpp_n, long double __lcpp_x) -{ - return __libcpp_laguerre(__lcpp_n ,__lcpp_x); -} - - -inline _LIBCPP_HIDE_FROM_ABI double legendre(unsigned __lcpp_n, double __lcpp_x) -{ - return __libcpp_legendre(__lcpp_n ,__lcpp_x); -} -inline _LIBCPP_HIDE_FROM_ABI float legendref(unsigned __lcpp_n, float __lcpp_x) -{ - return static_cast(__libcpp_legendre(__lcpp_n, static_cast(__lcpp_x))); -} -inline _LIBCPP_HIDE_FROM_ABI long double legendrel(unsigned __lcpp_n, long double __lcpp_x) -{ - return __libcpp_legendre(__lcpp_n ,__lcpp_x); -} inline _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __lcpp_n, double __lcpp_x) { diff --git a/libcxx/test/std/experimental/math/assoc_laguerre.pass.cpp b/libcxx/test/std/experimental/math/assoc_laguerre.pass.cpp deleted file mode 100644 index 793a723116d48..0000000000000 --- a/libcxx/test/std/experimental/math/assoc_laguerre.pass.cpp +++ /dev/null @@ -1,134 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// - -#include -#include -#include - -#if _LIBCPP_STD_VER > 14 - -template void testAssocLaguerreNaNPropagation() { - const unsigned MaxN = 127; - const T x = std::numeric_limits::quiet_NaN(); - for (unsigned n = 0; n <= MaxN; ++n) { - for (unsigned m = 0; m <= MaxN; ++m) { - assert(std::isnan(std::experimental::assoc_laguerre(n, m, x))); - } - } -} - -template void testAssocLaguerreNotNaN(const T x) { - assert(!std::isnan(x)); - const unsigned MaxN = 127; - for (unsigned n = 0; n <= MaxN; ++n) { - for (unsigned m = 0; m <= MaxN; ++m) { - assert(!std::isnan(std::experimental::assoc_laguerre(n, m, x))); - } - } -} - -template void testAssocLaguerreThrows(const T x) { -#ifndef _LIBCPP_NO_EXCEPTIONS - const unsigned MaxN = 127; - for (unsigned n = 0; n <= MaxN; ++n) { - for (unsigned m = 0; m <= MaxN; ++m) { - bool Throws = false; - try { - std::experimental::assoc_laguerre(n, m, x); - } catch (const std::domain_error &) { - Throws = true; - } - assert(Throws); - } - } -#endif // _LIBCPP_NO_EXCEPTIONS -} - -template -void testAssocLaguerreVsLaguerre(const T x, const T AbsTolerance, - const T RelTolerance) { - assert(!std::isnan(x)); - const unsigned MaxN = 127; - for (unsigned n = 0; n <= MaxN; ++n) { - for (unsigned m = 0; m <= MaxN; ++m) { - const T Result = std::experimental::assoc_laguerre(n, 0, x); - const T ExpectedResult = std::experimental::laguerre(n, x); - const T Tolerance = - AbsTolerance + std::abs(ExpectedResult) * RelTolerance; - const T Difference = std::abs(Result - ExpectedResult); - assert(Difference <= Tolerance); - } - } -} - -template -void testAssocLaguerreAnalytic(const T x, const T AbsTolerance, - const T RelTolerance) { - assert(!std::isnan(x)); - const auto compareFloatingPoint = - [AbsTolerance, RelTolerance](const T Result, const T ExpectedResult) { - if (std::isinf(ExpectedResult) && std::isinf(Result)) - return true; - - if (std::isnan(ExpectedResult) || std::isnan(Result)) - return false; - - const T Tolerance = - AbsTolerance + std::abs(ExpectedResult) * RelTolerance; - return std::abs(Result - ExpectedResult) < Tolerance; - }; - - const auto l0 = [](T, unsigned) { return T(1); }; - const auto l1 = [](T y, unsigned m) { return -y + T(m + 1); }; - const auto l2 = [](T y, unsigned m) { - return y * y / T(2) - T(m + 2) * y + T(m + 1) * T(m + 2) / T(2); - }; - const auto l3 = [](T y, unsigned m) { - return -y * y * y / T(6) + T(m + 3) * y * y / T(2) - - T(m + 2) * T(m + 3) * y / T(2) + - T(m + 1) * T(m + 2) * T(m + 3) / T(6); - }; - - for (unsigned m = 0; m < 128; ++m) { - assert(compareFloatingPoint(std::experimental::assoc_laguerre(0, m, x), - l0(x, m))); - assert(compareFloatingPoint(std::experimental::assoc_laguerre(1, m, x), - l1(x, m))); - assert(compareFloatingPoint(std::experimental::assoc_laguerre(2, m, x), - l2(x, m))); - assert(compareFloatingPoint(std::experimental::assoc_laguerre(3, m, x), - l3(x, m))); - } -} - -template -void testAssocLaguerre(const T AbsTolerance, const T RelTolerance) { - testAssocLaguerreNaNPropagation(); - testAssocLaguerreThrows(T(-5)); - - const T Samples[] = {T(0.0), T(0.1), T(0.5), T(1.0), T(10.0)}; - - for (T x : Samples) { - testAssocLaguerreNotNaN(x); - testAssocLaguerreAnalytic(x, AbsTolerance, RelTolerance); - testAssocLaguerreVsLaguerre(x, AbsTolerance, RelTolerance); - } -} - -#endif - -int main(int, char **) { -#if _LIBCPP_STD_VER > 14 - testAssocLaguerre(1e-5f, 1e-5f); - testAssocLaguerre(1e-9, 1e-9); - testAssocLaguerre(1e-12, 1e-12); -#endif - return 0; -} diff --git a/libcxx/test/std/experimental/math/assoc_legendre.pass.cpp b/libcxx/test/std/experimental/math/assoc_legendre.pass.cpp deleted file mode 100644 index ed9b1e1f9178d..0000000000000 --- a/libcxx/test/std/experimental/math/assoc_legendre.pass.cpp +++ /dev/null @@ -1,203 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// - -#include -#include -#include - -#if _LIBCPP_STD_VER > 14 - -template void testAssocLegendreNaNPropagation() { - const unsigned MaxN = 127; - const T x = std::numeric_limits::quiet_NaN(); - for (unsigned n = 0; n <= MaxN; ++n) { - for (unsigned m = 0; m <= MaxN; ++m) { - assert(std::isnan(std::experimental::assoc_legendre(n, m, x))); - } - } -} - -template void testAssocLegendreNotNaN(const T x) { - assert(!std::isnan(x)); - const unsigned MaxN = 127; - for (unsigned n = 0; n <= MaxN; ++n) { - for (unsigned m = 0; m <= MaxN; ++m) { - assert(!std::isnan(std::experimental::assoc_legendre(n, m, x))); - } - } -} - -template void testAssocLegendreThrows(const T x) { -#ifndef _LIBCPP_NO_EXCEPTIONS - const unsigned MaxN = 127; - for (unsigned n = 0; n <= MaxN; ++n) { - for (unsigned m = 0; m <= MaxN; ++m) { - bool Throws = false; - try { - std::experimental::assoc_legendre(n, m, x); - } catch (const std::domain_error &) { - Throws = true; - } - assert(Throws); - } - } -#endif // _LIBCPP_NO_EXCEPTIONS -} - -template -void testAssocLegendreVsLegendre(const T x, const T AbsTolerance, - const T RelTolerance) { - assert(!std::isnan(x)); - const unsigned MaxN = 127; - for (unsigned n = 0; n <= MaxN; ++n) { - for (unsigned m = 0; m <= MaxN; ++m) { - const T Result = std::experimental::assoc_legendre(n, 0, x); - const T ExpectedResult = std::experimental::legendre(n, x); - const T Tolerance = - AbsTolerance + std::abs(ExpectedResult) * RelTolerance; - const T Difference = std::abs(Result - ExpectedResult); - assert(Difference <= Tolerance); - } - } -} - -template -void testAssocLegendreAnalytic(const T x, const T AbsTolerance, - const T RelTolerance) { - assert(!std::isnan(x)); - const auto compareFloatingPoint = - [AbsTolerance, RelTolerance](const T Result, const T ExpectedResult) { - if (std::isinf(ExpectedResult) && std::isinf(Result)) - return true; - - if (std::isnan(ExpectedResult) || std::isnan(Result)) - return false; - - const T Tolerance = - AbsTolerance + std::abs(ExpectedResult) * RelTolerance; - return std::abs(Result - ExpectedResult) < Tolerance; - }; - - const auto l00 = [](T) { return T(1); }; - - const auto l10 = [](T y) { return y; }; - const auto l11 = [](T y) { return std::sqrt((T(1) - y) * (T(1) + y)); }; - - const auto l20 = [](T y) { return (T(3) * y * y - T(1)) / T(2); }; - const auto l21 = [](T y) { - return T(3) * y * std::sqrt((T(1) - y) * (T(1) + y)); - }; - const auto l22 = [](T y) { return T(3) * (T(1) - y) * (T(1) + y); }; - - const auto l30 = [](T y) { return (T(5) * y * y - T(3)) * y / T(2); }; - const auto l31 = [](T y) { - return T(3) / T(2) * (T(5) * y * y - T(1)) * - std::sqrt((T(1) - y) * (T(1) + y)); - }; - const auto l32 = [](T y) { return T(15) * y * (T(1) - y) * (T(1) + y); }; - const auto l33 = [](T y) { - const T temp = (T(1) - y) * (T(1) + y); - return T(15) * temp * std::sqrt(temp); - }; - - const auto l40 = [](T y) { - return (T(35) * y * y * y * y - T(30) * y * y + T(3)) / T(8); - }; - const auto l41 = [](T y) { - return T(5) / T(2) * y * (T(7) * y * y - T(3)) * - std::sqrt((T(1) - y) * (T(1) + y)); - }; - const auto l42 = [](T y) { - return T(15) / T(2) * (T(7) * y * y - 1) * (T(1) - y) * (T(1) + y); - }; - const auto l43 = [](T y) { - const T temp = (T(1) - y) * (T(1) + y); - return T(105) * y * temp * std::sqrt(temp); - }; - const auto l44 = [](T y) { - const T temp = (T(1) - y) * (T(1) + y); - return T(105) * temp * temp; - }; - - assert( - compareFloatingPoint(std::experimental::assoc_legendre(0, 0, x), l00(x))); - - assert( - compareFloatingPoint(std::experimental::assoc_legendre(1, 0, x), l10(x))); - assert( - compareFloatingPoint(std::experimental::assoc_legendre(1, 1, x), l11(x))); - - assert( - compareFloatingPoint(std::experimental::assoc_legendre(2, 0, x), l20(x))); - assert( - compareFloatingPoint(std::experimental::assoc_legendre(2, 1, x), l21(x))); - assert( - compareFloatingPoint(std::experimental::assoc_legendre(2, 2, x), l22(x))); - - assert( - compareFloatingPoint(std::experimental::assoc_legendre(3, 0, x), l30(x))); - assert( - compareFloatingPoint(std::experimental::assoc_legendre(3, 1, x), l31(x))); - assert( - compareFloatingPoint(std::experimental::assoc_legendre(3, 2, x), l32(x))); - assert( - compareFloatingPoint(std::experimental::assoc_legendre(3, 3, x), l33(x))); - - assert( - compareFloatingPoint(std::experimental::assoc_legendre(4, 0, x), l40(x))); - assert( - compareFloatingPoint(std::experimental::assoc_legendre(4, 1, x), l41(x))); - assert( - compareFloatingPoint(std::experimental::assoc_legendre(4, 2, x), l42(x))); - assert( - compareFloatingPoint(std::experimental::assoc_legendre(4, 3, x), l43(x))); - assert( - compareFloatingPoint(std::experimental::assoc_legendre(4, 4, x), l44(x))); - - try { - const unsigned MaxN = 127; - for (unsigned n = 0; n <= MaxN; ++n) { - for (unsigned m = n + 1; m <= MaxN; ++m) { - assert(std::experimental::assoc_legendre(n, m, x) <= AbsTolerance); - } - } - } catch (const std::domain_error &) { - // Should not throw! The expression given in - // ISO/IEC JTC 1/SC 22/WG 21 N3060 is actually well-defined for m > n! - assert(false); - } -} - -template -void testAssocLegendre(const T AbsTolerance, const T RelTolerance) { - testAssocLegendreNaNPropagation(); - testAssocLegendreThrows(T(-5)); - testAssocLegendreThrows(T(5)); - - const T Samples[] = {T(-1.0), T(-0.5), T(-0.1), T(0.0), - T(0.1), T(0.5), T(1.0)}; - - for (T x : Samples) { - testAssocLegendreNotNaN(x); - testAssocLegendreVsLegendre(x, AbsTolerance, RelTolerance); - testAssocLegendreAnalytic(x, AbsTolerance, RelTolerance); - } -} - -#endif - -int main(int, char **) { -#if _LIBCPP_STD_VER > 14 - testAssocLegendre(1e-6f, 1e-6f); - testAssocLegendre(1e-9, 1e-9); - testAssocLegendre(1e-12, 1e-12); -#endif - return 0; -} diff --git a/libcxx/test/std/experimental/math/laguerre.pass.cpp b/libcxx/test/std/experimental/math/laguerre.pass.cpp deleted file mode 100644 index f6a11221e2500..0000000000000 --- a/libcxx/test/std/experimental/math/laguerre.pass.cpp +++ /dev/null @@ -1,119 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// - -#include -#include -#include - -#if _LIBCPP_STD_VER > 14 - -template void testLaguerreNaNPropagation() { - const unsigned MaxN = 127; - const T x = std::numeric_limits::quiet_NaN(); - for (unsigned n = 0; n <= MaxN; ++n) { - assert(std::isnan(std::experimental::laguerre(n, x))); - } -} - -template void testLaguerreNotNaN(const T x) { - assert(!std::isnan(x)); - const unsigned MaxN = 127; - for (unsigned n = 0; n <= MaxN; ++n) { - assert(!std::isnan(std::experimental::laguerre(n, x))); - } -} - -template void testLaguerreThrows(const T x) { -#ifndef _LIBCPP_NO_EXCEPTIONS - const unsigned MaxN = 127; - for (unsigned n = 0; n <= MaxN; ++n) { - bool Throws = false; - try { - std::experimental::laguerre(n, x); - } catch (const std::domain_error &) { - Throws = true; - } - assert(Throws); - } -#endif // _LIBCPP_NO_EXCEPTIONS -} - -template -void testLaguerreAnalytic(const T x, const T AbsTolerance, - const T RelTolerance) { - assert(!std::isnan(x)); - const auto compareFloatingPoint = - [AbsTolerance, RelTolerance](const T Result, const T ExpectedResult) { - if (std::isinf(ExpectedResult) && std::isinf(Result)) - return true; - - if (std::isnan(ExpectedResult) || std::isnan(Result)) - return false; - - const T Tolerance = - AbsTolerance + std::abs(ExpectedResult) * RelTolerance; - return std::abs(Result - ExpectedResult) < Tolerance; - }; - - const auto l0 = [](T) { return T(1); }; - const auto l1 = [](T y) { return -y + 1; }; - const auto l2 = [](T y) { return (y * y - T(4) * y + T(2)) / T(2); }; - const auto l3 = [](T y) { - return (-y * y * y + T(9) * y * y - T(18) * y + T(6)) / T(6); - }; - const auto l4 = [](T y) { - return (y * y * y * y - T(16) * y * y * y + T(72) * y * y - T(96) * y + - T(24)) / - T(24); - }; - const auto l5 = [](T y) { - return (-y * y * y * y * y + T(25) * y * y * y * y - T(200) * y * y * y + - T(600) * y * y - T(600) * y + T(120)) / - T(120); - }; - const auto l6 = [](T y) { - return (y * y * y * y * y * y - T(36) * y * y * y * y * y + - T(450) * y * y * y * y - T(2400) * y * y * y + T(5400) * y * y - - T(4320) * y + T(720)) / - T(720); - }; - - assert(compareFloatingPoint(std::experimental::laguerre(0, x), l0(x))); - assert(compareFloatingPoint(std::experimental::laguerre(1, x), l1(x))); - assert(compareFloatingPoint(std::experimental::laguerre(2, x), l2(x))); - assert(compareFloatingPoint(std::experimental::laguerre(3, x), l3(x))); - assert(compareFloatingPoint(std::experimental::laguerre(4, x), l4(x))); - assert(compareFloatingPoint(std::experimental::laguerre(5, x), l5(x))); - assert(compareFloatingPoint(std::experimental::laguerre(6, x), l6(x))); -} - -template -void testLaguerre(const T AbsTolerance, const T RelTolerance) { - testLaguerreNaNPropagation(); - testLaguerreThrows(T(-5)); - - const T Samples[] = {T(0.0), T(0.1), T(0.5), T(1.0), T(10.0)}; - - for (T x : Samples) { - testLaguerreNotNaN(x); - testLaguerreAnalytic(x, AbsTolerance, RelTolerance); - } -} - -#endif - -int main(int, char **) { -#if _LIBCPP_STD_VER > 14 - testLaguerre(1e-6f, 1e-6f); - testLaguerre(1e-9, 1e-9); - testLaguerre(1e-12, 1e-12); -#endif - return 0; -} diff --git a/libcxx/test/std/experimental/math/legendre.pass.cpp b/libcxx/test/std/experimental/math/legendre.pass.cpp deleted file mode 100644 index 493b1c10f345f..0000000000000 --- a/libcxx/test/std/experimental/math/legendre.pass.cpp +++ /dev/null @@ -1,114 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// - -#include -#include -#include - -#if _LIBCPP_STD_VER > 14 - -template void testLegendreNaNPropagation() { - const unsigned MaxN = 127; - const T x = std::numeric_limits::quiet_NaN(); - for (unsigned n = 0; n <= MaxN; ++n) { - assert(std::isnan(std::experimental::legendre(n, x))); - } -} - -template void testLegendreNotNaN(const T x) { - assert(!std::isnan(x)); - const unsigned MaxN = 127; - for (unsigned n = 0; n <= MaxN; ++n) { - assert(!std::isnan(std::experimental::legendre(n, x))); - } -} - -template void testLegendreThrows(const T x) { -#ifndef _LIBCPP_NO_EXCEPTIONS - const unsigned MaxN = 127; - for (unsigned n = 0; n <= MaxN; ++n) { - bool Throws = false; - try { - std::experimental::legendre(n, x); - } catch (const std::domain_error &) { - Throws = true; - } - assert(Throws); - } -#endif // _LIBCPP_NO_EXCEPTIONS -} - -template -void testLegendreAnalytic(const T x, const T AbsTolerance, - const T RelTolerance) { - assert(!std::isnan(x)); - const auto compareFloatingPoint = - [AbsTolerance, RelTolerance](const T Result, const T ExpectedResult) { - if (std::isinf(ExpectedResult) && std::isinf(Result)) - return true; - - if (std::isnan(ExpectedResult) || std::isnan(Result)) - return false; - - const T Tolerance = - AbsTolerance + std::abs(ExpectedResult) * RelTolerance; - return std::abs(Result - ExpectedResult) < Tolerance; - }; - - const auto l0 = [](T) { return T(1); }; - const auto l1 = [](T y) { return y; }; - const auto l2 = [](T y) { return (T(3) * y * y - T(1)) / T(2); }; - const auto l3 = [](T y) { return (T(5) * y * y - T(3)) * y / T(2); }; - const auto l4 = [](T y) { - return (T(35) * y * y * y * y - T(30) * y * y + T(3)) / T(8); - }; - const auto l5 = [](T y) { - return (T(63) * y * y * y * y - T(70) * y * y + T(15)) * y / T(8); - }; - const auto l6 = [](T y) { - const T y2 = y * y; - return (T(231) * y2 * y2 * y2 - T(315) * y2 * y2 + T(105) * y2 - T(5)) / - T(16); - }; - - assert(compareFloatingPoint(std::experimental::legendre(0, x), l0(x))); - assert(compareFloatingPoint(std::experimental::legendre(1, x), l1(x))); - assert(compareFloatingPoint(std::experimental::legendre(2, x), l2(x))); - assert(compareFloatingPoint(std::experimental::legendre(3, x), l3(x))); - assert(compareFloatingPoint(std::experimental::legendre(4, x), l4(x))); - assert(compareFloatingPoint(std::experimental::legendre(5, x), l5(x))); - assert(compareFloatingPoint(std::experimental::legendre(6, x), l6(x))); -} - -template -void testLegendre(const T AbsTolerance, const T RelTolerance) { - testLegendreNaNPropagation(); - testLegendreThrows(T(-5)); - testLegendreThrows(T(5)); - - const T Samples[] = {T(-1.0), T(-0.5), T(-0.1), T(0.0), - T(0.1), T(0.5), T(1.0)}; - - for (T x : Samples) { - testLegendreNotNaN(x); - testLegendreAnalytic(x, AbsTolerance, RelTolerance); - } -} - -#endif - -int main(int, char **) { -#if _LIBCPP_STD_VER > 14 - testLegendre(1e-6f, 1e-6f); - testLegendre(1e-9, 1e-9); - testLegendre(1e-12, 1e-12); -#endif - return 0; -} From 622cb1adea7b42a9c236469098a8bf720306c593 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:01 +0200 Subject: [PATCH 17/80] remove explicit type conversions --- libcxx/include/experimental/__math/hermite.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libcxx/include/experimental/__math/hermite.h b/libcxx/include/experimental/__math/hermite.h index b89cb0b27b6d9..11eac3cfc691c 100644 --- a/libcxx/include/experimental/__math/hermite.h +++ b/libcxx/include/experimental/__math/hermite.h @@ -28,13 +28,13 @@ /// scientific computing. Cambridge university press, 2007, p. 183. template _Real __libcpp_hermite_recurrence(unsigned __n, _Real __x) { - if (0u == __n) - return _Real{1}; + if (0 == __n) + return 1; _Real __H_nPrev{1}; - _Real __H_n = _Real{2} * __x; + _Real __H_n = 2 * __x; for (unsigned __i = 1; __i < __n; ++__i) { - const _Real __H_nNext = _Real{2} * (__x * __H_n - _Real{__i} * __H_nPrev); + const _Real __H_nNext = 2 * (__x * __H_n - __i * __H_nPrev); __H_nPrev = __H_n; __H_n = __H_nNext; } From 23ffb72cab21f27f1eabbf64eb723b12352f95eb Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:01 +0200 Subject: [PATCH 18/80] use more readable variable names --- libcxx/include/experimental/math | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libcxx/include/experimental/math b/libcxx/include/experimental/math index a0a4f70ad4237..c9e39cb961c65 100644 --- a/libcxx/include/experimental/math +++ b/libcxx/include/experimental/math @@ -24,18 +24,18 @@ _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL -inline _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __lcpp_n, double __lcpp_x) +inline _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, double __x) { - return __libcpp_hermite(__lcpp_n ,__lcpp_x); + return __libcpp_hermite(__n, __x); } -inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __lcpp_n, float __lcpp_x) +inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __n, float __x) { // use double internally -- float is too prone to overflow! - return static_cast(__libcpp_hermite(__lcpp_n , static_cast(__lcpp_x))); + return static_cast(__libcpp_hermite(__n, static_cast(__x))); } -inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __lcpp_n, long double __lcpp_x) +inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __n, long double __x) { - return __libcpp_hermite(__lcpp_n ,__lcpp_x); + return __libcpp_hermite(__n, __x); } From 390947d8fec805583d2e8f0b659fd2aa313c5d39 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:02 +0200 Subject: [PATCH 19/80] make use of function template argument deduction --- libcxx/include/experimental/math | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/include/experimental/math b/libcxx/include/experimental/math index c9e39cb961c65..3039a90815919 100644 --- a/libcxx/include/experimental/math +++ b/libcxx/include/experimental/math @@ -26,7 +26,7 @@ _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL inline _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, double __x) { - return __libcpp_hermite(__n, __x); + return __libcpp_hermite(__n, __x); } inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __n, float __x) { @@ -35,7 +35,7 @@ inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __n, float __x) } inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __n, long double __x) { - return __libcpp_hermite(__n, __x); + return __libcpp_hermite(__n, __x); } From f9b489b67889f5573db687631af7cead1d836ce6 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:02 +0200 Subject: [PATCH 20/80] constness of passed arguments --- libcxx/include/experimental/__math/hermite.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/include/experimental/__math/hermite.h b/libcxx/include/experimental/__math/hermite.h index 11eac3cfc691c..09d12e4e17c29 100644 --- a/libcxx/include/experimental/__math/hermite.h +++ b/libcxx/include/experimental/__math/hermite.h @@ -27,7 +27,7 @@ /// Press, William H., et al. Numerical recipes 3rd edition: The art of /// scientific computing. Cambridge university press, 2007, p. 183. template -_Real __libcpp_hermite_recurrence(unsigned __n, _Real __x) { +_Real __libcpp_hermite_recurrence(const unsigned __n, const _Real __x) { if (0 == __n) return 1; @@ -41,7 +41,7 @@ _Real __libcpp_hermite_recurrence(unsigned __n, _Real __x) { return __H_n; } -template _Real __libcpp_hermite(unsigned __n, _Real __x) { +template _Real __libcpp_hermite(const unsigned __n, const _Real __x) { if (std::isnan(__x)) return std::numeric_limits<_Real>::quiet_NaN(); From cbcef2722495a55818f5dffed9cb01119432adc8 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:02 +0200 Subject: [PATCH 21/80] unify return path via ternary op --- libcxx/include/experimental/__math/hermite.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libcxx/include/experimental/__math/hermite.h b/libcxx/include/experimental/__math/hermite.h index 09d12e4e17c29..a1ad77c32a4ec 100644 --- a/libcxx/include/experimental/__math/hermite.h +++ b/libcxx/include/experimental/__math/hermite.h @@ -42,10 +42,9 @@ _Real __libcpp_hermite_recurrence(const unsigned __n, const _Real __x) { } template _Real __libcpp_hermite(const unsigned __n, const _Real __x) { - if (std::isnan(__x)) - return std::numeric_limits<_Real>::quiet_NaN(); - - return __libcpp_hermite_recurrence(__n, __x); + return std::isnan(__x) + ? std::numeric_limits<_Real>::quiet_NaN() + : __libcpp_hermite_recurrence(__n, __x); } #endif // _LIBCPP_EXPERIMENTAL___MATH_HERMITE_H From 48268c901a51756b02dcb7da1097f6dc1182e7dc Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:03 +0200 Subject: [PATCH 22/80] clang format --- libcxx/include/experimental/__math/hermite.h | 13 ++- libcxx/include/experimental/math | 23 ++--- .../std/experimental/math/hermite.pass.cpp | 94 +++++++------------ 3 files changed, 50 insertions(+), 80 deletions(-) diff --git a/libcxx/include/experimental/__math/hermite.h b/libcxx/include/experimental/__math/hermite.h index a1ad77c32a4ec..b95e7a084ff87 100644 --- a/libcxx/include/experimental/__math/hermite.h +++ b/libcxx/include/experimental/__math/hermite.h @@ -15,8 +15,8 @@ #ifndef _LIBCPP_EXPERIMENTAL___MATH_HERMITE_H #define _LIBCPP_EXPERIMENTAL___MATH_HERMITE_H -#include #include +#include #include /// \return the hermite polynomial \f$ H_{n}(x) \f$ @@ -35,16 +35,15 @@ _Real __libcpp_hermite_recurrence(const unsigned __n, const _Real __x) { _Real __H_n = 2 * __x; for (unsigned __i = 1; __i < __n; ++__i) { const _Real __H_nNext = 2 * (__x * __H_n - __i * __H_nPrev); - __H_nPrev = __H_n; - __H_n = __H_nNext; + __H_nPrev = __H_n; + __H_n = __H_nNext; } return __H_n; } -template _Real __libcpp_hermite(const unsigned __n, const _Real __x) { - return std::isnan(__x) - ? std::numeric_limits<_Real>::quiet_NaN() - : __libcpp_hermite_recurrence(__n, __x); +template +_Real __libcpp_hermite(const unsigned __n, const _Real __x) { + return std::isnan(__x) ? std::numeric_limits<_Real>::quiet_NaN() : __libcpp_hermite_recurrence(__n, __x); } #endif // _LIBCPP_EXPERIMENTAL___MATH_HERMITE_H diff --git a/libcxx/include/experimental/math b/libcxx/include/experimental/math index 3039a90815919..604a573281666 100644 --- a/libcxx/include/experimental/math +++ b/libcxx/include/experimental/math @@ -12,32 +12,25 @@ // The following macro name shall be conditionally defined by the implementation // to indicate conformance to the International Standard ISO/IEC JTC 1/SC 22/WG 21 N3060 -//#define __STDCPP_MATH_SPEC_FUNCS__ 201003L +// #define __STDCPP_MATH_SPEC_FUNCS__ 201003L -#include #include +#include #if _LIBCPP_STD_VER > 14 -#include +# include _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL +inline _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, double __x) { return __libcpp_hermite(__n, __x); } -inline _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, double __x) -{ - return __libcpp_hermite(__n, __x); -} -inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __n, float __x) -{ - // use double internally -- float is too prone to overflow! - return static_cast(__libcpp_hermite(__n, static_cast(__x))); -} -inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __n, long double __x) -{ - return __libcpp_hermite(__n, __x); +inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __n, float __x) { + // use double internally -- float is too prone to overflow! + return static_cast(__libcpp_hermite(__n, static_cast(__x))); } +inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __n, long double __x) { return __libcpp_hermite(__n, __x); } _LIBCPP_END_NAMESPACE_EXPERIMENTAL diff --git a/libcxx/test/std/experimental/math/hermite.pass.cpp b/libcxx/test/std/experimental/math/hermite.pass.cpp index 06522cdcb5d32..6347da68fe22d 100644 --- a/libcxx/test/std/experimental/math/hermite.pass.cpp +++ b/libcxx/test/std/experimental/math/hermite.pass.cpp @@ -16,15 +16,17 @@ #if _LIBCPP_STD_VER > 14 -template void testHermiteNaNPropagation() { +template +void testHermiteNaNPropagation() { const unsigned MaxN = 127; - const T x = std::numeric_limits::quiet_NaN(); + const T x = std::numeric_limits::quiet_NaN(); for (unsigned n = 0; n <= MaxN; ++n) { assert(std::isnan(std::experimental::hermite(n, x))); } } -template void testHermiteNotNaN(const T x) { +template +void testHermiteNotNaN(const T x) { assert(!std::isnan(x)); const unsigned MaxN = 127; for (unsigned n = 0; n <= MaxN; ++n) { @@ -33,31 +35,25 @@ template void testHermiteNotNaN(const T x) { } template -void testHermiteAnalytic(const T x, const T AbsTolerance, - const T RelTolerance) { +void testHermiteAnalytic(const T x, const T AbsTolerance, const T RelTolerance) { assert(!std::isnan(x)); - const auto compareFloatingPoint = - [AbsTolerance, RelTolerance](const T Result, const T Expected) { - if (std::isinf(Expected) && std::isinf(Result)) - return true; + const auto compareFloatingPoint = [AbsTolerance, RelTolerance](const T Result, const T Expected) { + if (std::isinf(Expected) && std::isinf(Result)) + return true; - if (std::isnan(Expected) || std::isnan(Result)) - return false; + if (std::isnan(Expected) || std::isnan(Result)) + return false; - const T Tolerance = AbsTolerance + std::abs(Expected) * RelTolerance; - return std::abs(Result - Expected) < Tolerance; - }; + const T Tolerance = AbsTolerance + std::abs(Expected) * RelTolerance; + return std::abs(Result - Expected) < Tolerance; + }; const auto h0 = [](T) { return T(1); }; const auto h1 = [](T y) { return T(2) * y; }; const auto h2 = [](T y) { return T(4) * y * y - T(2); }; const auto h3 = [](T y) { return y * (T(8) * y * y - T(12)); }; - const auto h4 = [](T y) { - return (T(16) * y * y * y * y - T(48) * y * y + T(12)); - }; - const auto h5 = [](T y) { - return y * (T(32) * y * y * y * y - T(160) * y * y + T(120)); - }; + const auto h4 = [](T y) { return (T(16) * y * y * y * y - T(48) * y * y + T(12)); }; + const auto h5 = [](T y) { return y * (T(32) * y * y * y * y - T(160) * y * y + T(120)); }; assert(compareFloatingPoint(std::experimental::hermite(0, x), h0(x))); assert(compareFloatingPoint(std::experimental::hermite(1, x), h1(x))); @@ -77,10 +73,9 @@ void testRecurrenceRelation(T x, T RelTolerance, T AbsTolerance) { for (unsigned n = 1; n < MaxN; ++n) { const T HermiteNext = std::experimental::hermite(n + 1, x); const T HermiteNextRecurrence = - T(2) * x * std::experimental::hermite(n, x) - - T(2) * T(n) * std::experimental::hermite(n - 1, x); + T(2) * x * std::experimental::hermite(n, x) - T(2) * T(n) * std::experimental::hermite(n - 1, x); const T Tolerance = AbsTolerance + std::abs(HermiteNext) * RelTolerance; - const T Error = std::abs(HermiteNextRecurrence - HermiteNext); + const T Error = std::abs(HermiteNextRecurrence - HermiteNext); if (std::isinf(HermiteNext)) break; @@ -88,9 +83,9 @@ void testRecurrenceRelation(T x, T RelTolerance, T AbsTolerance) { } } -template void testRecurrenceRelation(T RelTolerance, T AbsTolerance) { - const T Samples[] = {T(-1.0), T(-0.5), T(-0.1), T(0.0), - T(0.1), T(0.5), T(1.0)}; +template +void testRecurrenceRelation(T RelTolerance, T AbsTolerance) { + const T Samples[] = {T(-1.0), T(-0.5), T(-0.1), T(0.0), T(0.1), T(0.5), T(1.0)}; for (T x : Samples) testRecurrenceRelation(x, RelTolerance, AbsTolerance); } @@ -99,7 +94,8 @@ template void testRecurrenceRelation(T RelTolerance, T AbsTolerance) { /// Salzer, Herbert E., Ruth Zucker, and Ruth Capuano. /// Table of the zeros and weight factors of the first twenty Hermite /// polynomials. US Government Printing Office, 1952. -template std::vector getHermiteRoots(unsigned n) { +template +std::vector getHermiteRoots(unsigned n) { if (n == 0u) return {}; if (n == 1u) @@ -107,40 +103,22 @@ template std::vector getHermiteRoots(unsigned n) { if (n == 2u) return {T(0.707106781186548)}; if (n == 3u) - return {T(0), - T(1.224744871391589)}; + return {T(0), T(1.224744871391589)}; if (n == 4u) - return {T(0.524647623275290), - T(1.650680123885785)}; + return {T(0.524647623275290), T(1.650680123885785)}; if (n == 5u) - return {T(0), T(0.958572464613819), - T(2.020182870456086)}; + return {T(0), T(0.958572464613819), T(2.020182870456086)}; if (n == 6u) - return {T(0.436077411927617), - T(1.335849074013697), - T(2.350604973674492)}; + return {T(0.436077411927617), T(1.335849074013697), T(2.350604973674492)}; if (n == 7u) - return {T(0), - T(0.816287882858965), - T(1.673551628767471), - T(2.651961356835233)}; + return {T(0), T(0.816287882858965), T(1.673551628767471), T(2.651961356835233)}; if (n == 8u) - return {T(0.381186990207322), - T(1.157193712446780), - T(1.981656756695843), - T(2.930637420257244)}; + return {T(0.381186990207322), T(1.157193712446780), T(1.981656756695843), T(2.930637420257244)}; if (n == 9u) - return {T(0), - T(0.723551018752838), - T(1.468553289216668), - T(2.266580584531843), - T(3.190993201781528)}; + return {T(0), T(0.723551018752838), T(1.468553289216668), T(2.266580584531843), T(3.190993201781528)}; if (n == 10u) - return {T(0.342901327223705), - T(1.036610829789514), - T(1.756683649299882), - T(2.532731674232790), - T(3.436159118837738)}; + return { + T(0.342901327223705), T(1.036610829789514), T(1.756683649299882), T(2.532731674232790), T(3.436159118837738)}; if (n == 11u) return {T(0), T(0.65680956682100), @@ -244,7 +222,8 @@ template std::vector getHermiteRoots(unsigned n) { /// \param [in] Tolerance of the root. This value must be smaller than /// the smallest difference between adjacent roots in the given range /// with n <= 20. -template void testHermiteRoots(T Tolerance) { +template +void testHermiteRoots(T Tolerance) { for (unsigned n = 0; n <= 20u; ++n) { const auto Roots = getHermiteRoots(n); for (T x : Roots) { @@ -261,8 +240,7 @@ template void testHermiteRoots(T Tolerance) { template void testHermite(const T AbsTolerance, const T RelTolerance) { testHermiteNaNPropagation(); - const T Samples[] = {T(-1.0), T(-0.5), T(-0.1), T(0.0), - T(0.1), T(0.5), T(1.0)}; + const T Samples[] = {T(-1.0), T(-0.5), T(-0.1), T(0.0), T(0.1), T(0.5), T(1.0)}; for (T x : Samples) { testHermiteNotNaN(x); @@ -272,7 +250,7 @@ void testHermite(const T AbsTolerance, const T RelTolerance) { #endif -int main(int, char **) { +int main(int, char**) { #if _LIBCPP_STD_VER > 14 testHermite(1e-6f, 1e-6f); testHermite(1e-9, 1e-9); From 7c4a14a6a9bfd5f49298d9a5ae2ff4cc4c93b25c Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:03 +0200 Subject: [PATCH 23/80] cleanup preprocessor usage --- libcxx/include/experimental/__math/hermite.h | 4 ++-- libcxx/include/experimental/math | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/libcxx/include/experimental/__math/hermite.h b/libcxx/include/experimental/__math/hermite.h index b95e7a084ff87..23bc7b452cdfe 100644 --- a/libcxx/include/experimental/__math/hermite.h +++ b/libcxx/include/experimental/__math/hermite.h @@ -15,9 +15,9 @@ #ifndef _LIBCPP_EXPERIMENTAL___MATH_HERMITE_H #define _LIBCPP_EXPERIMENTAL___MATH_HERMITE_H -#include +#include // std::isnan #include -#include +#include // std::numeric_limits /// \return the hermite polynomial \f$ H_{n}(x) \f$ /// \note The implementation is based on the recurrence formula diff --git a/libcxx/include/experimental/math b/libcxx/include/experimental/math index 604a573281666..3b0703fb4bca5 100644 --- a/libcxx/include/experimental/math +++ b/libcxx/include/experimental/math @@ -14,10 +14,9 @@ // to indicate conformance to the International Standard ISO/IEC JTC 1/SC 22/WG 21 N3060 // #define __STDCPP_MATH_SPEC_FUNCS__ 201003L -#include #include -#if _LIBCPP_STD_VER > 14 +#if _LIBCPP_STD_VER >= 17 # include @@ -34,6 +33,6 @@ inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __n, long double __x) _LIBCPP_END_NAMESPACE_EXPERIMENTAL -#endif // _LIBCPP_STD_VER > 14 +#endif // _LIBCPP_STD_VER >= 17 #endif // _LIBCPP_EXPERIMENTAL_MATH From 57cdb0403bbf7c9cd90170d13f4bf511e4556f86 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:03 +0200 Subject: [PATCH 24/80] sufficient additional overloads by LWG 3234 --- libcxx/include/experimental/math | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libcxx/include/experimental/math b/libcxx/include/experimental/math index 3b0703fb4bca5..5161381be0b61 100644 --- a/libcxx/include/experimental/math +++ b/libcxx/include/experimental/math @@ -24,12 +24,16 @@ _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL inline _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, double __x) { return __libcpp_hermite(__n, __x); } -inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __n, float __x) { +inline _LIBCPP_HIDE_FROM_ABI float hermite(unsigned __n, float __x) { // use double internally -- float is too prone to overflow! return static_cast(__libcpp_hermite(__n, static_cast(__x))); } -inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __n, long double __x) { return __libcpp_hermite(__n, __x); } +inline _LIBCPP_HIDE_FROM_ABI long double hermite(unsigned __n, long double __x) { return __libcpp_hermite(__n, __x); } + +inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __n, float __x) { return hermite(__n, __x); } + +inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __n, long double __x) { return hermite(__n, __x); } _LIBCPP_END_NAMESPACE_EXPERIMENTAL From a42128e7922009f8e8e09ab55cb5902f9b188266 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:04 +0200 Subject: [PATCH 25/80] simplify hermite(float) --- libcxx/include/experimental/math | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/include/experimental/math b/libcxx/include/experimental/math index 5161381be0b61..2c633ff32df6d 100644 --- a/libcxx/include/experimental/math +++ b/libcxx/include/experimental/math @@ -26,7 +26,7 @@ inline _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, double __x) { return _ inline _LIBCPP_HIDE_FROM_ABI float hermite(unsigned __n, float __x) { // use double internally -- float is too prone to overflow! - return static_cast(__libcpp_hermite(__n, static_cast(__x))); + return static_cast(hermite(__n, static_cast(__x))); } inline _LIBCPP_HIDE_FROM_ABI long double hermite(unsigned __n, long double __x) { return __libcpp_hermite(__n, __x); } From d0500d9bbcace01a084eade863b4dbfc0f8bd8e2 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:04 +0200 Subject: [PATCH 26/80] implement: template double hermite(unsigned, Integer) --- libcxx/include/experimental/math | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libcxx/include/experimental/math b/libcxx/include/experimental/math index 2c633ff32df6d..21cf2a00d92fe 100644 --- a/libcxx/include/experimental/math +++ b/libcxx/include/experimental/math @@ -19,6 +19,7 @@ #if _LIBCPP_STD_VER >= 17 # include +# include // enable_if_t, is_integral_v _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL @@ -35,6 +36,12 @@ inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __n, float __x) { return he inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __n, long double __x) { return hermite(__n, __x); } +template < class _Integer > +_LIBCPP_HIDE_FROM_ABI std::enable_if_t, double> hermite(unsigned int __n, _Integer __x) { + // use double internally -- see C++17 standard - 29.9.1.2.2 + return hermite(__n, static_cast(__x)); +} + _LIBCPP_END_NAMESPACE_EXPERIMENTAL #endif // _LIBCPP_STD_VER >= 17 From 711a757075b2c5fc0f5e0260c7d7fd46114a2739 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:04 +0200 Subject: [PATCH 27/80] remove old comment --- libcxx/include/experimental/math | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libcxx/include/experimental/math b/libcxx/include/experimental/math index 21cf2a00d92fe..b7847d5037bb6 100644 --- a/libcxx/include/experimental/math +++ b/libcxx/include/experimental/math @@ -10,10 +10,6 @@ #ifndef _LIBCPP_EXPERIMENTAL_MATH #define _LIBCPP_EXPERIMENTAL_MATH -// The following macro name shall be conditionally defined by the implementation -// to indicate conformance to the International Standard ISO/IEC JTC 1/SC 22/WG 21 N3060 -// #define __STDCPP_MATH_SPEC_FUNCS__ 201003L - #include #if _LIBCPP_STD_VER >= 17 From ece1daf9c1b7dae2bbcd27f756f06c9df0c8edac Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:05 +0200 Subject: [PATCH 28/80] make use of Lit: // UNSUPPORTED: c++XX --- libcxx/test/std/experimental/math/hermite.pass.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/libcxx/test/std/experimental/math/hermite.pass.cpp b/libcxx/test/std/experimental/math/hermite.pass.cpp index 6347da68fe22d..27c25ffb737c7 100644 --- a/libcxx/test/std/experimental/math/hermite.pass.cpp +++ b/libcxx/test/std/experimental/math/hermite.pass.cpp @@ -14,7 +14,7 @@ #include #include -#if _LIBCPP_STD_VER > 14 +// UNSUPPORTED: c++03, c++11, c++14 template void testHermiteNaNPropagation() { @@ -248,10 +248,7 @@ void testHermite(const T AbsTolerance, const T RelTolerance) { } } -#endif - int main(int, char**) { -#if _LIBCPP_STD_VER > 14 testHermite(1e-6f, 1e-6f); testHermite(1e-9, 1e-9); testHermite(1e-12l, 1e-12l); @@ -263,6 +260,6 @@ int main(int, char**) { testHermiteRoots(1e-6f); testHermiteRoots(1e-9); testHermiteRoots(1e-10l); -#endif + return 0; } From 5bba7f147038b7c8ec69e0c02e4d26278ccad952 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:05 +0200 Subject: [PATCH 29/80] cleanup tests --- .../std/experimental/math/hermite.pass.cpp | 88 +++++++++++++------ 1 file changed, 63 insertions(+), 25 deletions(-) diff --git a/libcxx/test/std/experimental/math/hermite.pass.cpp b/libcxx/test/std/experimental/math/hermite.pass.cpp index 27c25ffb737c7..dc4f7163808eb 100644 --- a/libcxx/test/std/experimental/math/hermite.pass.cpp +++ b/libcxx/test/std/experimental/math/hermite.pass.cpp @@ -13,15 +13,21 @@ #include #include #include +#include + +#include // UNSUPPORTED: c++03, c++11, c++14 +namespace { +namespace ex = std::experimental; + template void testHermiteNaNPropagation() { const unsigned MaxN = 127; const T x = std::numeric_limits::quiet_NaN(); for (unsigned n = 0; n <= MaxN; ++n) { - assert(std::isnan(std::experimental::hermite(n, x))); + assert(std::isnan(ex::hermite(n, x))); } } @@ -30,7 +36,7 @@ void testHermiteNotNaN(const T x) { assert(!std::isnan(x)); const unsigned MaxN = 127; for (unsigned n = 0; n <= MaxN; ++n) { - assert(!std::isnan(std::experimental::hermite(n, x))); + assert(!std::isnan(ex::hermite(n, x))); } } @@ -55,12 +61,12 @@ void testHermiteAnalytic(const T x, const T AbsTolerance, const T RelTolerance) const auto h4 = [](T y) { return (T(16) * y * y * y * y - T(48) * y * y + T(12)); }; const auto h5 = [](T y) { return y * (T(32) * y * y * y * y - T(160) * y * y + T(120)); }; - assert(compareFloatingPoint(std::experimental::hermite(0, x), h0(x))); - assert(compareFloatingPoint(std::experimental::hermite(1, x), h1(x))); - assert(compareFloatingPoint(std::experimental::hermite(2, x), h2(x))); - assert(compareFloatingPoint(std::experimental::hermite(3, x), h3(x))); - assert(compareFloatingPoint(std::experimental::hermite(4, x), h4(x))); - assert(compareFloatingPoint(std::experimental::hermite(5, x), h5(x))); + assert(compareFloatingPoint(ex::hermite(0, x), h0(x))); + assert(compareFloatingPoint(ex::hermite(1, x), h1(x))); + assert(compareFloatingPoint(ex::hermite(2, x), h2(x))); + assert(compareFloatingPoint(ex::hermite(3, x), h3(x))); + assert(compareFloatingPoint(ex::hermite(4, x), h4(x))); + assert(compareFloatingPoint(ex::hermite(5, x), h5(x))); } /// \details This method checks if the following recurrence relation holds: @@ -68,14 +74,13 @@ void testHermiteAnalytic(const T x, const T AbsTolerance, const T RelTolerance) /// H_{n+1}(x) = 2x H_{n}(x) - 2n H_{n-1}(x) /// \f] template -void testRecurrenceRelation(T x, T RelTolerance, T AbsTolerance) { +void testRecurrenceRelation(T x, T AbsTolerance, T RelTolerance) { const unsigned MaxN = 127; for (unsigned n = 1; n < MaxN; ++n) { - const T HermiteNext = std::experimental::hermite(n + 1, x); - const T HermiteNextRecurrence = - T(2) * x * std::experimental::hermite(n, x) - T(2) * T(n) * std::experimental::hermite(n - 1, x); - const T Tolerance = AbsTolerance + std::abs(HermiteNext) * RelTolerance; - const T Error = std::abs(HermiteNextRecurrence - HermiteNext); + const T HermiteNext = ex::hermite(n + 1, x); + const T HermiteNextRecurrence = T(2) * (x * ex::hermite(n, x) - T(n) * ex::hermite(n - 1, x)); + const T Tolerance = AbsTolerance + std::abs(HermiteNext) * RelTolerance; + const T Error = std::abs(HermiteNextRecurrence - HermiteNext); if (std::isinf(HermiteNext)) break; @@ -84,10 +89,10 @@ void testRecurrenceRelation(T x, T RelTolerance, T AbsTolerance) { } template -void testRecurrenceRelation(T RelTolerance, T AbsTolerance) { +void testRecurrenceRelation(T AbsTolerance, T RelTolerance) { const T Samples[] = {T(-1.0), T(-0.5), T(-0.1), T(0.0), T(0.1), T(0.5), T(1.0)}; for (T x : Samples) - testRecurrenceRelation(x, RelTolerance, AbsTolerance); + testRecurrenceRelation(x, AbsTolerance, RelTolerance); } /// \note Roots are taken from @@ -229,10 +234,8 @@ void testHermiteRoots(T Tolerance) { for (T x : Roots) { // the roots are symmetric: if x is a root, so is -x if (x > T(0)) - assert(std::signbit(std::experimental::hermite(n, -x + Tolerance)) != - std::signbit(std::experimental::hermite(n, -x - Tolerance))); - assert(std::signbit(std::experimental::hermite(n, x + Tolerance)) != - std::signbit(std::experimental::hermite(n, x - Tolerance))); + assert(std::signbit(ex::hermite(n, -x + Tolerance)) != std::signbit(ex::hermite(n, -x - Tolerance))); + assert(std::signbit(ex::hermite(n, x + Tolerance)) != std::signbit(ex::hermite(n, x - Tolerance))); } } } @@ -248,18 +251,53 @@ void testHermite(const T AbsTolerance, const T RelTolerance) { } } +template +void testHermiteByInteger() { + const unsigned nMax = 128; + for (unsigned n = 0; n < nMax; ++n) + for (Integer x : {-1, 0, 1}) + assert(ex::hermite(n, x) == ex::hermite(n, static_cast(x))); +} + +void testHermiteF() { + const unsigned nMax = 128; + const std::array samples{-1.0f, -0.5f, -0.1f, 0.0f, 0.1f, 0.5f, 1.0f}; + + for (unsigned n = 0; n < nMax; ++n) + for (float x : samples) + assert(ex::hermite(n, x) == ex::hermitef(n, x)); +} + +void testHermiteL() { + const unsigned nMax = 128; + const std::array samples{-1.0l, -0.5l, -0.1l, 0.0l, 0.1l, 0.5l, 1.0l}; + + for (unsigned n = 0; n < nMax; ++n) + for (long double x : samples) + assert(ex::hermite(n, x) == ex::hermitel(n, x)); +} +} // namespace + int main(int, char**) { - testHermite(1e-6f, 1e-6f); - testHermite(1e-9, 1e-9); + testHermite(1e-5f, 1e-5f); + testHermite(1e-11, 1e-11); testHermite(1e-12l, 1e-12l); - testRecurrenceRelation(1e-6f, 1e-6f); - testRecurrenceRelation(1e-9, 1e-9); + testHermiteF(); + testHermiteL(); + + testRecurrenceRelation(1e-5f, 1e-5f); + testRecurrenceRelation(1e-11, 1e-11); testRecurrenceRelation(1e-12l, 1e-12l); - testHermiteRoots(1e-6f); + testHermiteRoots(1e-5f); testHermiteRoots(1e-9); testHermiteRoots(1e-10l); + testHermiteByInteger(); + testHermiteByInteger(); + testHermiteByInteger(); + testHermiteByInteger(); + return 0; } From 6f0006b43e4f0cb62e0e881f869cfe43bfd3faae Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:05 +0200 Subject: [PATCH 30/80] update docs/Status --- libcxx/docs/Status/Cxx17Papers.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/docs/Status/Cxx17Papers.csv b/libcxx/docs/Status/Cxx17Papers.csv index 2e560cfe0d576..aab710ce785ff 100644 --- a/libcxx/docs/Status/Cxx17Papers.csv +++ b/libcxx/docs/Status/Cxx17Papers.csv @@ -26,7 +26,7 @@ "`P0013R1 `__","LWG","Logical type traits rev 2","Kona","|Complete|","3.8" "","","","","","" "`P0024R2 `__","LWG","The Parallelism TS Should be Standardized","Jacksonville","|Partial|","" -"`P0226R1 `__","LWG","Mathematical Special Functions for C++17","Jacksonville","","" +"`P0226R1 `__","LWG","Mathematical Special Functions for C++17","Jacksonville","|In Progress|","" "`P0220R1 `__","LWG","Adopt Library Fundamentals V1 TS Components for C++17","Jacksonville","|Complete|","16.0" "`P0218R1 `__","LWG","Adopt the File System TS for C++17","Jacksonville","|Complete|","7.0" "`P0033R1 `__","LWG","Re-enabling shared_from_this","Jacksonville","|Complete|","3.9" From b60044d6c35ba98db81023004012775218c00a84 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:06 +0200 Subject: [PATCH 31/80] modulemap include private headers --- libcxx/include/module.modulemap | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 297c687fbc896..3833fe4246ddb 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -522,6 +522,8 @@ module std_experimental [system] { export * } module math { + module hermite { private header "experimental/__math/hermite.h" } + header "experimental/math" export * } From e33c6d98c2a40de8ddec459dc718b35c22a414e5 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:06 +0200 Subject: [PATCH 32/80] remove doxygen style file comment --- libcxx/include/experimental/__math/hermite.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libcxx/include/experimental/__math/hermite.h b/libcxx/include/experimental/__math/hermite.h index 23bc7b452cdfe..7fecfae514131 100644 --- a/libcxx/include/experimental/__math/hermite.h +++ b/libcxx/include/experimental/__math/hermite.h @@ -6,11 +6,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// -/// -/// \file -/// This file contains the internal implementations of std::hermite. -/// -//===----------------------------------------------------------------------===// #ifndef _LIBCPP_EXPERIMENTAL___MATH_HERMITE_H #define _LIBCPP_EXPERIMENTAL___MATH_HERMITE_H From 135e5e749ae07e96308add1b56f867549bf877f0 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:06 +0200 Subject: [PATCH 33/80] move out of experimental/ --- libcxx/include/CMakeLists.txt | 2 - libcxx/include/cmath | 202 ++++++++++++++++++ libcxx/include/experimental/__math/hermite.h | 44 ---- libcxx/include/experimental/math | 45 ---- libcxx/include/module.modulemap | 6 - .../math => numerics/c.math}/hermite.pass.cpp | 34 ++- 6 files changed, 218 insertions(+), 115 deletions(-) delete mode 100644 libcxx/include/experimental/__math/hermite.h delete mode 100644 libcxx/include/experimental/math rename libcxx/test/std/{experimental/math => numerics/c.math}/hermite.pass.cpp (88%) diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 3837506bc295f..07dd25604a9c7 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -919,7 +919,6 @@ set(files execution expected experimental/__config - experimental/__math/hermite.h experimental/__simd/aligned_tag.h experimental/__simd/declaration.h experimental/__simd/reference.h @@ -930,7 +929,6 @@ set(files experimental/__simd/utility.h experimental/__simd/vec_ext.h experimental/iterator - experimental/math experimental/memory experimental/propagate_const experimental/simd diff --git a/libcxx/include/cmath b/libcxx/include/cmath index 7a87e35c84603..43fc6e2e95586 100644 --- a/libcxx/include/cmath +++ b/libcxx/include/cmath @@ -610,6 +610,208 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool __constexpr_isfinite(_A1 __lcpp_x) return __builtin_isfinite(__lcpp_x); } +_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI float __constexpr_copysign(float __x, float __y) _NOEXCEPT { + return __builtin_copysignf(__x, __y); +} + +_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI double __constexpr_copysign(double __x, double __y) _NOEXCEPT { + return __builtin_copysign(__x, __y); +} + +_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI long double +__constexpr_copysign(long double __x, long double __y) _NOEXCEPT { + return __builtin_copysignl(__x, __y); +} + +template ::value && std::is_arithmetic<_A2>::value, int> = 0> +_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI typename __promote<_A1, _A2>::type +__constexpr_copysign(_A1 __x, _A2 __y) _NOEXCEPT { + typedef typename std::__promote<_A1, _A2>::type __result_type; + static_assert((!(std::_IsSame<_A1, __result_type>::value && std::_IsSame<_A2, __result_type>::value)), ""); + return __builtin_copysign((__result_type)__x, (__result_type)__y); +} + +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR float __constexpr_fabs(float __x) _NOEXCEPT { + return __builtin_fabsf(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR double __constexpr_fabs(double __x) _NOEXCEPT { + return __builtin_fabs(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR long double __constexpr_fabs(long double __x) _NOEXCEPT { + return __builtin_fabsl(__x); +} + +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR double __constexpr_fabs(_Tp __x) _NOEXCEPT { + return __builtin_fabs(static_cast(__x)); +} + +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 float __constexpr_fmax(float __x, float __y) _NOEXCEPT { +#if !__has_constexpr_builtin(__builtin_fmaxf) + if (__libcpp_is_constant_evaluated()) { + if (std::__constexpr_isnan(__x)) + return __y; + if (std::__constexpr_isnan(__y)) + return __x; + return __x < __y ? __y : __x; + } +#endif + return __builtin_fmaxf(__x, __y); +} + +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 double __constexpr_fmax(double __x, double __y) _NOEXCEPT { +#if !__has_constexpr_builtin(__builtin_fmax) + if (__libcpp_is_constant_evaluated()) { + if (std::__constexpr_isnan(__x)) + return __y; + if (std::__constexpr_isnan(__y)) + return __x; + return __x < __y ? __y : __x; + } +#endif + return __builtin_fmax(__x, __y); +} + +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 long double +__constexpr_fmax(long double __x, long double __y) _NOEXCEPT { +#if !__has_constexpr_builtin(__builtin_fmaxl) + if (__libcpp_is_constant_evaluated()) { + if (std::__constexpr_isnan(__x)) + return __y; + if (std::__constexpr_isnan(__y)) + return __x; + return __x < __y ? __y : __x; + } +#endif + return __builtin_fmaxl(__x, __y); +} + +template ::value && is_arithmetic<_Up>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename __promote<_Tp, _Up>::type +__constexpr_fmax(_Tp __x, _Up __y) _NOEXCEPT { + using __result_type = typename __promote<_Tp, _Up>::type; + return std::__constexpr_fmax(static_cast<__result_type>(__x), static_cast<__result_type>(__y)); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __constexpr_logb(_Tp __x) { +#if !__has_constexpr_builtin(__builtin_logb) + if (__libcpp_is_constant_evaluated()) { + if (__x == _Tp(0)) { + // raise FE_DIVBYZERO + return -numeric_limits<_Tp>::infinity(); + } + + if (std::__constexpr_isinf(__x)) + return numeric_limits<_Tp>::infinity(); + + if (std::__constexpr_isnan(__x)) + return numeric_limits<_Tp>::quiet_NaN(); + + __x = std::__constexpr_fabs(__x); + unsigned long long __exp = 0; + while (__x >= numeric_limits<_Tp>::radix) { + __x /= numeric_limits<_Tp>::radix; + __exp += 1; + } + return _Tp(__exp); + } +#endif // !__has_constexpr_builtin(__builtin_logb) + return __builtin_logb(__x); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp __constexpr_scalbn(_Tp __x, int __exp) { +#if !__has_constexpr_builtin(__builtin_scalbln) + if (__libcpp_is_constant_evaluated()) { + if (__x == _Tp(0)) + return __x; + + if (std::__constexpr_isinf(__x)) + return __x; + + if (__exp == _Tp(0)) + return __x; + + if (std::__constexpr_isnan(__x)) + return numeric_limits<_Tp>::quiet_NaN(); + + _Tp __mult(1); + if (__exp > 0) { + __mult = numeric_limits<_Tp>::radix; + --__exp; + } else { + ++__exp; + __exp = -__exp; + __mult /= numeric_limits<_Tp>::radix; + } + + while (__exp > 0) { + if (!(__exp & 1)) { + __mult *= __mult; + __exp >>= 1; + } else { + __x *= __mult; + --__exp; + } + } + return __x; + } +#endif // !__has_constexpr_builtin(__builtin_scalbln) + return __builtin_scalbn(__x, __exp); +} + +#if _LIBCPP_STD_VER >= 17 + +/// \return the Hermite polynomial \f$ H_n(x) \f$ +/// \note The implementation is based on the recurrence formula +/// \f[ +/// H_{n+1}(x) = 2x H_n(x) - 2n H_{n-1} +/// \f] +/// Press, William H., et al. Numerical recipes 3rd edition: The art of +/// scientific computing. Cambridge university press, 2007, p. 183. +template +_Real __libcpp_hermite(unsigned __n, _Real __x) { + if (std::isnan(__x)) + return std::numeric_limits<_Real>::quiet_NaN(); + + if (0 == __n) + return 1; + + _Real __H_nPrev{1}; + _Real __H_n = 2 * __x; + for (unsigned __i = 1; __i < __n; ++__i) { + const _Real __H_nNext = 2 * (__x * __H_n - __i * __H_nPrev); + __H_nPrev = __H_n; + __H_n = __H_nNext; + } + return __H_n; +} + +inline _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, double __x) { return __libcpp_hermite(__n, __x); } + +inline _LIBCPP_HIDE_FROM_ABI float hermite(unsigned __n, float __x) { + // use double internally -- float is too prone to overflow! + return static_cast(hermite(__n, static_cast(__x))); +} + +inline _LIBCPP_HIDE_FROM_ABI long double hermite(unsigned __n, long double __x) { return __libcpp_hermite(__n, __x); } + +inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __n, float __x) { return hermite(__n, __x); } + +inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __n, long double __x) { return hermite(__n, __x); } + +template < class _Integer > +_LIBCPP_HIDE_FROM_ABI std::enable_if_t, double> hermite(unsigned int __n, _Integer __x) { + // use double internally -- see C++17 standard - 29.9.1.2.2 + return hermite(__n, static_cast(__x)); +} +#endif // _LIBCPP_STD_VER >= 17 + #if _LIBCPP_STD_VER >= 20 template _LIBCPP_HIDE_FROM_ABI constexpr _Fp __lerp(_Fp __a, _Fp __b, _Fp __t) noexcept { diff --git a/libcxx/include/experimental/__math/hermite.h b/libcxx/include/experimental/__math/hermite.h deleted file mode 100644 index 7fecfae514131..0000000000000 --- a/libcxx/include/experimental/__math/hermite.h +++ /dev/null @@ -1,44 +0,0 @@ -// -*- C++ -*- -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef _LIBCPP_EXPERIMENTAL___MATH_HERMITE_H -#define _LIBCPP_EXPERIMENTAL___MATH_HERMITE_H - -#include // std::isnan -#include -#include // std::numeric_limits - -/// \return the hermite polynomial \f$ H_{n}(x) \f$ -/// \note The implementation is based on the recurrence formula -/// \f[ -/// H_{n+1}(x) = 2x H_{n}(x) - 2 n H_{n-1} -/// \f] -/// Press, William H., et al. Numerical recipes 3rd edition: The art of -/// scientific computing. Cambridge university press, 2007, p. 183. -template -_Real __libcpp_hermite_recurrence(const unsigned __n, const _Real __x) { - if (0 == __n) - return 1; - - _Real __H_nPrev{1}; - _Real __H_n = 2 * __x; - for (unsigned __i = 1; __i < __n; ++__i) { - const _Real __H_nNext = 2 * (__x * __H_n - __i * __H_nPrev); - __H_nPrev = __H_n; - __H_n = __H_nNext; - } - return __H_n; -} - -template -_Real __libcpp_hermite(const unsigned __n, const _Real __x) { - return std::isnan(__x) ? std::numeric_limits<_Real>::quiet_NaN() : __libcpp_hermite_recurrence(__n, __x); -} - -#endif // _LIBCPP_EXPERIMENTAL___MATH_HERMITE_H diff --git a/libcxx/include/experimental/math b/libcxx/include/experimental/math deleted file mode 100644 index b7847d5037bb6..0000000000000 --- a/libcxx/include/experimental/math +++ /dev/null @@ -1,45 +0,0 @@ -// -*- C++ -*- -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef _LIBCPP_EXPERIMENTAL_MATH -#define _LIBCPP_EXPERIMENTAL_MATH - -#include - -#if _LIBCPP_STD_VER >= 17 - -# include -# include // enable_if_t, is_integral_v - -_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL - -inline _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, double __x) { return __libcpp_hermite(__n, __x); } - -inline _LIBCPP_HIDE_FROM_ABI float hermite(unsigned __n, float __x) { - // use double internally -- float is too prone to overflow! - return static_cast(hermite(__n, static_cast(__x))); -} - -inline _LIBCPP_HIDE_FROM_ABI long double hermite(unsigned __n, long double __x) { return __libcpp_hermite(__n, __x); } - -inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __n, float __x) { return hermite(__n, __x); } - -inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __n, long double __x) { return hermite(__n, __x); } - -template < class _Integer > -_LIBCPP_HIDE_FROM_ABI std::enable_if_t, double> hermite(unsigned int __n, _Integer __x) { - // use double internally -- see C++17 standard - 29.9.1.2.2 - return hermite(__n, static_cast(__x)); -} - -_LIBCPP_END_NAMESPACE_EXPERIMENTAL - -#endif // _LIBCPP_STD_VER >= 17 - -#endif // _LIBCPP_EXPERIMENTAL_MATH diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 3833fe4246ddb..4ad506781c489 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -521,12 +521,6 @@ module std_experimental [system] { header "experimental/iterator" export * } - module math { - module hermite { private header "experimental/__math/hermite.h" } - - header "experimental/math" - export * - } module memory { header "experimental/memory" export * diff --git a/libcxx/test/std/experimental/math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp similarity index 88% rename from libcxx/test/std/experimental/math/hermite.pass.cpp rename to libcxx/test/std/numerics/c.math/hermite.pass.cpp index dc4f7163808eb..1067f431dbff7 100644 --- a/libcxx/test/std/experimental/math/hermite.pass.cpp +++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp @@ -9,7 +9,7 @@ // #include -#include +#include #include #include #include @@ -20,14 +20,12 @@ // UNSUPPORTED: c++03, c++11, c++14 namespace { -namespace ex = std::experimental; - template void testHermiteNaNPropagation() { const unsigned MaxN = 127; const T x = std::numeric_limits::quiet_NaN(); for (unsigned n = 0; n <= MaxN; ++n) { - assert(std::isnan(ex::hermite(n, x))); + assert(std::isnan(std::hermite(n, x))); } } @@ -36,7 +34,7 @@ void testHermiteNotNaN(const T x) { assert(!std::isnan(x)); const unsigned MaxN = 127; for (unsigned n = 0; n <= MaxN; ++n) { - assert(!std::isnan(ex::hermite(n, x))); + assert(!std::isnan(std::hermite(n, x))); } } @@ -61,12 +59,12 @@ void testHermiteAnalytic(const T x, const T AbsTolerance, const T RelTolerance) const auto h4 = [](T y) { return (T(16) * y * y * y * y - T(48) * y * y + T(12)); }; const auto h5 = [](T y) { return y * (T(32) * y * y * y * y - T(160) * y * y + T(120)); }; - assert(compareFloatingPoint(ex::hermite(0, x), h0(x))); - assert(compareFloatingPoint(ex::hermite(1, x), h1(x))); - assert(compareFloatingPoint(ex::hermite(2, x), h2(x))); - assert(compareFloatingPoint(ex::hermite(3, x), h3(x))); - assert(compareFloatingPoint(ex::hermite(4, x), h4(x))); - assert(compareFloatingPoint(ex::hermite(5, x), h5(x))); + assert(compareFloatingPoint(std::hermite(0, x), h0(x))); + assert(compareFloatingPoint(std::hermite(1, x), h1(x))); + assert(compareFloatingPoint(std::hermite(2, x), h2(x))); + assert(compareFloatingPoint(std::hermite(3, x), h3(x))); + assert(compareFloatingPoint(std::hermite(4, x), h4(x))); + assert(compareFloatingPoint(std::hermite(5, x), h5(x))); } /// \details This method checks if the following recurrence relation holds: @@ -77,8 +75,8 @@ template void testRecurrenceRelation(T x, T AbsTolerance, T RelTolerance) { const unsigned MaxN = 127; for (unsigned n = 1; n < MaxN; ++n) { - const T HermiteNext = ex::hermite(n + 1, x); - const T HermiteNextRecurrence = T(2) * (x * ex::hermite(n, x) - T(n) * ex::hermite(n - 1, x)); + const T HermiteNext = std::hermite(n + 1, x); + const T HermiteNextRecurrence = T(2) * (x * std::hermite(n, x) - T(n) * std::hermite(n - 1, x)); const T Tolerance = AbsTolerance + std::abs(HermiteNext) * RelTolerance; const T Error = std::abs(HermiteNextRecurrence - HermiteNext); @@ -234,8 +232,8 @@ void testHermiteRoots(T Tolerance) { for (T x : Roots) { // the roots are symmetric: if x is a root, so is -x if (x > T(0)) - assert(std::signbit(ex::hermite(n, -x + Tolerance)) != std::signbit(ex::hermite(n, -x - Tolerance))); - assert(std::signbit(ex::hermite(n, x + Tolerance)) != std::signbit(ex::hermite(n, x - Tolerance))); + assert(std::signbit(std::hermite(n, -x + Tolerance)) != std::signbit(std::hermite(n, -x - Tolerance))); + assert(std::signbit(std::hermite(n, x + Tolerance)) != std::signbit(std::hermite(n, x - Tolerance))); } } } @@ -256,7 +254,7 @@ void testHermiteByInteger() { const unsigned nMax = 128; for (unsigned n = 0; n < nMax; ++n) for (Integer x : {-1, 0, 1}) - assert(ex::hermite(n, x) == ex::hermite(n, static_cast(x))); + assert(std::hermite(n, x) == std::hermite(n, static_cast(x))); } void testHermiteF() { @@ -265,7 +263,7 @@ void testHermiteF() { for (unsigned n = 0; n < nMax; ++n) for (float x : samples) - assert(ex::hermite(n, x) == ex::hermitef(n, x)); + assert(std::hermite(n, x) == std::hermitef(n, x)); } void testHermiteL() { @@ -274,7 +272,7 @@ void testHermiteL() { for (unsigned n = 0; n < nMax; ++n) for (long double x : samples) - assert(ex::hermite(n, x) == ex::hermitel(n, x)); + assert(std::hermite(n, x) == std::hermitel(n, x)); } } // namespace From 161349b9ccab48023cac0b149274330f5d45a417 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:07 +0200 Subject: [PATCH 34/80] all functions need _LIBCPP_HIDE_FROM_API --- libcxx/include/cmath | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/include/cmath b/libcxx/include/cmath index 43fc6e2e95586..5f10aebbf4164 100644 --- a/libcxx/include/cmath +++ b/libcxx/include/cmath @@ -775,7 +775,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp __constexpr_scalbn(_Tp _ /// Press, William H., et al. Numerical recipes 3rd edition: The art of /// scientific computing. Cambridge university press, 2007, p. 183. template -_Real __libcpp_hermite(unsigned __n, _Real __x) { +_LIBCPP_HIDE_FROM_ABI _Real __libcpp_hermite(unsigned __n, _Real __x) { if (std::isnan(__x)) return std::numeric_limits<_Real>::quiet_NaN(); From f87416cdc038a54d1889bddeeb32f02a1957518b Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:07 +0200 Subject: [PATCH 35/80] remove `std::` similar to other surrounding code --- libcxx/include/cmath | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libcxx/include/cmath b/libcxx/include/cmath index 5f10aebbf4164..5c049a96a3a5c 100644 --- a/libcxx/include/cmath +++ b/libcxx/include/cmath @@ -776,8 +776,8 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp __constexpr_scalbn(_Tp _ /// scientific computing. Cambridge university press, 2007, p. 183. template _LIBCPP_HIDE_FROM_ABI _Real __libcpp_hermite(unsigned __n, _Real __x) { - if (std::isnan(__x)) - return std::numeric_limits<_Real>::quiet_NaN(); + if (isnan(__x)) + return numeric_limits<_Real>::quiet_NaN(); if (0 == __n) return 1; @@ -806,7 +806,7 @@ inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __n, float __x) { return he inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __n, long double __x) { return hermite(__n, __x); } template < class _Integer > -_LIBCPP_HIDE_FROM_ABI std::enable_if_t, double> hermite(unsigned int __n, _Integer __x) { +_LIBCPP_HIDE_FROM_ABI enable_if_t, double> hermite(unsigned int __n, _Integer __x) { // use double internally -- see C++17 standard - 29.9.1.2.2 return hermite(__n, static_cast(__x)); } From 12574b81eeb685a16ec57f4a04e2ca770d5c874a Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:07 +0200 Subject: [PATCH 36/80] include missing header: type_traits/is_integral --- libcxx/include/cmath | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/include/cmath b/libcxx/include/cmath index 5c049a96a3a5c..2e5cbca3d8dcb 100644 --- a/libcxx/include/cmath +++ b/libcxx/include/cmath @@ -309,6 +309,7 @@ constexpr long double lerp(long double a, long double b, long double t) noexcept #include <__type_traits/is_arithmetic.h> #include <__type_traits/is_constant_evaluated.h> #include <__type_traits/is_floating_point.h> +#include <__type_traits/is_integral.h> #include <__type_traits/is_same.h> #include <__type_traits/promote.h> #include <__type_traits/remove_cv.h> From 6199348bf69ae98abdcbee13c2be6b6505129c49 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:08 +0200 Subject: [PATCH 37/80] test: place Lit comment correctly --- libcxx/test/std/numerics/c.math/hermite.pass.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp index 1067f431dbff7..e26a4d9542da8 100644 --- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp +++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// +// UNSUPPORTED: c++03, c++11, c++14 #include #include @@ -17,7 +17,6 @@ #include -// UNSUPPORTED: c++03, c++11, c++14 namespace { template From 6f5e9eb3b58f5bdd4a4a3d611b6f6ef6614e31a0 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:08 +0200 Subject: [PATCH 38/80] don't use yoda conditional --- libcxx/include/cmath | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/include/cmath b/libcxx/include/cmath index 2e5cbca3d8dcb..5c7243ad310c3 100644 --- a/libcxx/include/cmath +++ b/libcxx/include/cmath @@ -780,7 +780,7 @@ _LIBCPP_HIDE_FROM_ABI _Real __libcpp_hermite(unsigned __n, _Real __x) { if (isnan(__x)) return numeric_limits<_Real>::quiet_NaN(); - if (0 == __n) + if (__n == 0) return 1; _Real __H_nPrev{1}; From adbe52be0a9499571af7d11ea10ec49f1f27cdba Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:08 +0200 Subject: [PATCH 39/80] edits according to mentioned style issues --- libcxx/include/cmath | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/libcxx/include/cmath b/libcxx/include/cmath index 5c7243ad310c3..674b141c266e8 100644 --- a/libcxx/include/cmath +++ b/libcxx/include/cmath @@ -780,15 +780,16 @@ _LIBCPP_HIDE_FROM_ABI _Real __libcpp_hermite(unsigned __n, _Real __x) { if (isnan(__x)) return numeric_limits<_Real>::quiet_NaN(); + _Real __H_0{1}; if (__n == 0) - return 1; + return __H_0; - _Real __H_nPrev{1}; - _Real __H_n = 2 * __x; + _Real __H_n_prev = __H_0; + _Real __H_n = 2 * __x; for (unsigned __i = 1; __i < __n; ++__i) { - const _Real __H_nNext = 2 * (__x * __H_n - __i * __H_nPrev); - __H_nPrev = __H_n; - __H_n = __H_nNext; + _Real __H_n_next = 2 * (__x * __H_n - __i * __H_n_prev); + __H_n_prev = __H_n; + __H_n = __H_n_next; } return __H_n; } From aca72ce1c3f36a25b93a37aa8914ecfcd957ba2a Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:09 +0200 Subject: [PATCH 40/80] shorten internal hermite function's name --- libcxx/include/cmath | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libcxx/include/cmath b/libcxx/include/cmath index 674b141c266e8..8b6f73cf117fb 100644 --- a/libcxx/include/cmath +++ b/libcxx/include/cmath @@ -776,7 +776,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp __constexpr_scalbn(_Tp _ /// Press, William H., et al. Numerical recipes 3rd edition: The art of /// scientific computing. Cambridge university press, 2007, p. 183. template -_LIBCPP_HIDE_FROM_ABI _Real __libcpp_hermite(unsigned __n, _Real __x) { +_LIBCPP_HIDE_FROM_ABI _Real __hermite(unsigned __n, _Real __x) { if (isnan(__x)) return numeric_limits<_Real>::quiet_NaN(); @@ -794,14 +794,14 @@ _LIBCPP_HIDE_FROM_ABI _Real __libcpp_hermite(unsigned __n, _Real __x) { return __H_n; } -inline _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, double __x) { return __libcpp_hermite(__n, __x); } +inline _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, double __x) { return __hermite(__n, __x); } inline _LIBCPP_HIDE_FROM_ABI float hermite(unsigned __n, float __x) { // use double internally -- float is too prone to overflow! return static_cast(hermite(__n, static_cast(__x))); } -inline _LIBCPP_HIDE_FROM_ABI long double hermite(unsigned __n, long double __x) { return __libcpp_hermite(__n, __x); } +inline _LIBCPP_HIDE_FROM_ABI long double hermite(unsigned __n, long double __x) { return __hermite(__n, __x); } inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __n, float __x) { return hermite(__n, __x); } From 445f6b145ec138425eba9450544b6a009ccd4e0b Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:09 +0200 Subject: [PATCH 41/80] style format of template argument --- libcxx/include/cmath | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/include/cmath b/libcxx/include/cmath index 8b6f73cf117fb..eb4156f48779f 100644 --- a/libcxx/include/cmath +++ b/libcxx/include/cmath @@ -807,7 +807,7 @@ inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __n, float __x) { return he inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __n, long double __x) { return hermite(__n, __x); } -template < class _Integer > +template _LIBCPP_HIDE_FROM_ABI enable_if_t, double> hermite(unsigned int __n, _Integer __x) { // use double internally -- see C++17 standard - 29.9.1.2.2 return hermite(__n, static_cast(__x)); From b2aa559e77d4811c031b1e7dcc423da5574d2182 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:09 +0200 Subject: [PATCH 42/80] fully qualify function calls --- libcxx/include/cmath | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libcxx/include/cmath b/libcxx/include/cmath index eb4156f48779f..35b603ded5f45 100644 --- a/libcxx/include/cmath +++ b/libcxx/include/cmath @@ -777,8 +777,8 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp __constexpr_scalbn(_Tp _ /// scientific computing. Cambridge university press, 2007, p. 183. template _LIBCPP_HIDE_FROM_ABI _Real __hermite(unsigned __n, _Real __x) { - if (isnan(__x)) - return numeric_limits<_Real>::quiet_NaN(); + if (std::isnan(__x)) + return std::numeric_limits<_Real>::quiet_NaN(); _Real __H_0{1}; if (__n == 0) @@ -794,23 +794,23 @@ _LIBCPP_HIDE_FROM_ABI _Real __hermite(unsigned __n, _Real __x) { return __H_n; } -inline _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, double __x) { return __hermite(__n, __x); } +inline _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, double __x) { return std::__hermite(__n, __x); } inline _LIBCPP_HIDE_FROM_ABI float hermite(unsigned __n, float __x) { // use double internally -- float is too prone to overflow! - return static_cast(hermite(__n, static_cast(__x))); + return static_cast(std::hermite(__n, static_cast(__x))); } -inline _LIBCPP_HIDE_FROM_ABI long double hermite(unsigned __n, long double __x) { return __hermite(__n, __x); } +inline _LIBCPP_HIDE_FROM_ABI long double hermite(unsigned __n, long double __x) { return std::__hermite(__n, __x); } -inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __n, float __x) { return hermite(__n, __x); } +inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __n, float __x) { return std::hermite(__n, __x); } -inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __n, long double __x) { return hermite(__n, __x); } +inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __n, long double __x) { return std::hermite(__n, __x); } template -_LIBCPP_HIDE_FROM_ABI enable_if_t, double> hermite(unsigned int __n, _Integer __x) { +_LIBCPP_HIDE_FROM_ABI std::enable_if_t, double> hermite(unsigned int __n, _Integer __x) { // use double internally -- see C++17 standard - 29.9.1.2.2 - return hermite(__n, static_cast(__x)); + return std::hermite(__n, static_cast(__x)); } #endif // _LIBCPP_STD_VER >= 17 From 9fb7f783163324d7f94c6cd9b3bf97cacdc1ffee Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:10 +0200 Subject: [PATCH 43/80] test: style changes, renaming, etc. --- .../test/std/numerics/c.math/hermite.pass.cpp | 236 +++++++++--------- 1 file changed, 123 insertions(+), 113 deletions(-) diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp index e26a4d9542da8..397046219bb1f 100644 --- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp +++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp @@ -10,86 +10,95 @@ #include #include -#include #include #include #include #include - namespace { + +inline constexpr unsigned MAX_N = 128; + template -void testHermiteNaNPropagation() { - const unsigned MaxN = 127; - const T x = std::numeric_limits::quiet_NaN(); - for (unsigned n = 0; n <= MaxN; ++n) { - assert(std::isnan(std::hermite(n, x))); - } +std::array sample_points() { + return {-1.0, -0.5, -0.1, 0.0, 0.1, 0.5, 1.0}; +} + +template +void test_NaN_propagation() { + T NaN = std::numeric_limits::quiet_NaN(); + for (unsigned n = 0; n < MAX_N; ++n) + assert(std::isnan(std::hermite(n, NaN))); } template -void testHermiteNotNaN(const T x) { +void test_not_NaN(T x) { assert(!std::isnan(x)); - const unsigned MaxN = 127; - for (unsigned n = 0; n <= MaxN; ++n) { + for (unsigned n = 0; n < MAX_N; ++n) assert(!std::isnan(std::hermite(n, x))); - } } template -void testHermiteAnalytic(const T x, const T AbsTolerance, const T RelTolerance) { - assert(!std::isnan(x)); - const auto compareFloatingPoint = [AbsTolerance, RelTolerance](const T Result, const T Expected) { - if (std::isinf(Expected) && std::isinf(Result)) +struct CompareFloatingValues { + T abs_tol; + T rel_tol; + + bool operator()(T result, T expected) const { + if (std::isinf(expected) && std::isinf(result)) return true; - if (std::isnan(Expected) || std::isnan(Result)) + if (std::isnan(expected) || std::isnan(result)) return false; - const T Tolerance = AbsTolerance + std::abs(Expected) * RelTolerance; - return std::abs(Result - Expected) < Tolerance; - }; + T tol = abs_tol + std::abs(expected) * rel_tol; + return std::abs(result - expected) < tol; + } +}; + +template +void test_analytic_solution(T x, T abs_tol, T rel_tol) { + assert(!std::isnan(x)); - const auto h0 = [](T) { return T(1); }; - const auto h1 = [](T y) { return T(2) * y; }; - const auto h2 = [](T y) { return T(4) * y * y - T(2); }; - const auto h3 = [](T y) { return y * (T(8) * y * y - T(12)); }; - const auto h4 = [](T y) { return (T(16) * y * y * y * y - T(48) * y * y + T(12)); }; - const auto h5 = [](T y) { return y * (T(32) * y * y * y * y - T(160) * y * y + T(120)); }; - - assert(compareFloatingPoint(std::hermite(0, x), h0(x))); - assert(compareFloatingPoint(std::hermite(1, x), h1(x))); - assert(compareFloatingPoint(std::hermite(2, x), h2(x))); - assert(compareFloatingPoint(std::hermite(3, x), h3(x))); - assert(compareFloatingPoint(std::hermite(4, x), h4(x))); - assert(compareFloatingPoint(std::hermite(5, x), h5(x))); + const auto h0 = [](T) -> T { return 1; }; + const auto h1 = [](T y) -> T { return 2 * y; }; + const auto h2 = [](T y) -> T { return 4 * y * y - 2; }; + const auto h3 = [](T y) -> T { return y * (8 * y * y - 12); }; + const auto h4 = [](T y) -> T { return (16 * std::pow(y, 4) - 48 * y * y + 12); }; + const auto h5 = [](T y) -> T { return y * (32 * std::pow(y, 4) - 160 * y * y + 120); }; + + const CompareFloatingValues compare{.abs_tol = abs_tol, .rel_tol = rel_tol}; + assert(compare(std::hermite(0, x), h0(x))); + assert(compare(std::hermite(1, x), h1(x))); + assert(compare(std::hermite(2, x), h2(x))); + assert(compare(std::hermite(3, x), h3(x))); + assert(compare(std::hermite(4, x), h4(x))); + assert(compare(std::hermite(5, x), h5(x))); } /// \details This method checks if the following recurrence relation holds: /// \f[ -/// H_{n+1}(x) = 2x H_{n}(x) - 2n H_{n-1}(x) +/// H_{n+1}(x) = 2x H_n(x) - 2n H_{n-1}(x) /// \f] template -void testRecurrenceRelation(T x, T AbsTolerance, T RelTolerance) { - const unsigned MaxN = 127; - for (unsigned n = 1; n < MaxN; ++n) { - const T HermiteNext = std::hermite(n + 1, x); - const T HermiteNextRecurrence = T(2) * (x * std::hermite(n, x) - T(n) * std::hermite(n - 1, x)); - const T Tolerance = AbsTolerance + std::abs(HermiteNext) * RelTolerance; - const T Error = std::abs(HermiteNextRecurrence - HermiteNext); - - if (std::isinf(HermiteNext)) +void test_recurrence_relation(T x, T abs_tol, T rel_tol) { + assert(!std::isnan(x)); + + const CompareFloatingValues compare{.abs_tol = abs_tol, .rel_tol = rel_tol}; + for (unsigned n = 1; n < MAX_N - 1; ++n) { + T H_next = std::hermite(n + 1, x); + T H_next_recurrence = 2 * (x * std::hermite(n, x) - n * std::hermite(n - 1, x)); + + if (std::isinf(H_next)) break; - assert(Error < Tolerance); + assert(compare(H_next, H_next_recurrence)); } } template -void testRecurrenceRelation(T AbsTolerance, T RelTolerance) { - const T Samples[] = {T(-1.0), T(-0.5), T(-0.1), T(0.0), T(0.1), T(0.5), T(1.0)}; - for (T x : Samples) - testRecurrenceRelation(x, AbsTolerance, RelTolerance); +void test_recurrence_relation(T abs_tol, T rel_tol) { + for (T x : sample_points()) + test_recurrence_relation(x, abs_tol, rel_tol); } /// \note Roots are taken from @@ -97,31 +106,32 @@ void testRecurrenceRelation(T AbsTolerance, T RelTolerance) { /// Table of the zeros and weight factors of the first twenty Hermite /// polynomials. US Government Printing Office, 1952. template -std::vector getHermiteRoots(unsigned n) { - if (n == 0u) +std::vector get_roots(unsigned n) { + switch (n) { + case 0: return {}; - if (n == 1u) + case 1: return {T(0)}; - if (n == 2u) + case 2: return {T(0.707106781186548)}; - if (n == 3u) + case 3: return {T(0), T(1.224744871391589)}; - if (n == 4u) + case 4: return {T(0.524647623275290), T(1.650680123885785)}; - if (n == 5u) + case 5: return {T(0), T(0.958572464613819), T(2.020182870456086)}; - if (n == 6u) + case 6: return {T(0.436077411927617), T(1.335849074013697), T(2.350604973674492)}; - if (n == 7u) + case 7: return {T(0), T(0.816287882858965), T(1.673551628767471), T(2.651961356835233)}; - if (n == 8u) + case 8: return {T(0.381186990207322), T(1.157193712446780), T(1.981656756695843), T(2.930637420257244)}; - if (n == 9u) + case 9: return {T(0), T(0.723551018752838), T(1.468553289216668), T(2.266580584531843), T(3.190993201781528)}; - if (n == 10u) + case 10: return { T(0.342901327223705), T(1.036610829789514), T(1.756683649299882), T(2.532731674232790), T(3.436159118837738)}; - if (n == 11u) + case 11: return {T(0), T(0.65680956682100), T(1.326557084494933), @@ -129,7 +139,7 @@ std::vector getHermiteRoots(unsigned n) { T(2.783290099781652), T(3.668470846559583)}; - if (n == 12u) + case 12: return {T(0.314240376254359), T(0.947788391240164), T(1.597682635152605), @@ -137,7 +147,7 @@ std::vector getHermiteRoots(unsigned n) { T(3.020637025120890), T(3.889724897869782)}; - if (n == 13u) + case 13: return {T(0), T(0.605763879171060), T(1.220055036590748), @@ -146,7 +156,7 @@ std::vector getHermiteRoots(unsigned n) { T(3.246608978372410), T(4.101337596178640)}; - if (n == 14u) + case 14: return {T(0.29174551067256), T(0.87871378732940), T(1.47668273114114), @@ -155,7 +165,7 @@ std::vector getHermiteRoots(unsigned n) { T(3.46265693360227), T(4.30444857047363)}; - if (n == 15u) + case 15: return {T(0.00000000000000), T(0.56506958325558), T(1.13611558521092), @@ -165,7 +175,7 @@ std::vector getHermiteRoots(unsigned n) { T(3.66995037340445), T(4.49999070730939)}; - if (n == 16u) + case 16: return {T(0.27348104613815), T(0.82295144914466), T(1.38025853919888), @@ -175,7 +185,7 @@ std::vector getHermiteRoots(unsigned n) { T(3.86944790486012), T(4.68873893930582)}; - if (n == 17u) + case 17: return {T(0), T(0.5316330013427), T(1.0676487257435), @@ -185,7 +195,8 @@ std::vector getHermiteRoots(unsigned n) { T(3.3789320911415), T(4.0619466758755), T(4.8713451936744)}; - if (n == 18u) + + case 18: return {T(0.2582677505191), T(0.7766829192674), T(1.3009208583896), @@ -195,7 +206,8 @@ std::vector getHermiteRoots(unsigned n) { T(3.5737690684863), T(4.2481178735681), T(5.0483640088745)}; - if (n == 19u) + + case 19: return {T(0), T(0.5035201634239), T(1.0103683871343), @@ -206,7 +218,8 @@ std::vector getHermiteRoots(unsigned n) { T(3.7621873519640), T(4.4285328066038), T(5.2202716905375)}; - if (n == 20u) + + case 20: return {T(0.2453407083009), T(0.7374737285454), T(1.2340762153953), @@ -218,83 +231,80 @@ std::vector getHermiteRoots(unsigned n) { T(4.6036824495507), T(5.3874808900112)}; - return {}; + default: + throw "Roots of Hermite polynomial of order " + std::to_string(n) + " not implemented!\n"; + } } /// \param [in] Tolerance of the root. This value must be smaller than /// the smallest difference between adjacent roots in the given range /// with n <= 20. template -void testHermiteRoots(T Tolerance) { +void test_roots(T Tolerance) { + const auto is_sign_change = [Tolerance](unsigned n, T x) -> bool { + return std::hermite(n, x - Tolerance) * std::hermite(n, x + Tolerance) < 0; + }; + for (unsigned n = 0; n <= 20u; ++n) { - const auto Roots = getHermiteRoots(n); - for (T x : Roots) { + for (T x : get_roots(n)) { // the roots are symmetric: if x is a root, so is -x - if (x > T(0)) - assert(std::signbit(std::hermite(n, -x + Tolerance)) != std::signbit(std::hermite(n, -x - Tolerance))); - assert(std::signbit(std::hermite(n, x + Tolerance)) != std::signbit(std::hermite(n, x - Tolerance))); + if (x > 0) + assert(is_sign_change(n, -x)); + assert(is_sign_change(n, x)); } } } template -void testHermite(const T AbsTolerance, const T RelTolerance) { - testHermiteNaNPropagation(); - const T Samples[] = {T(-1.0), T(-0.5), T(-0.1), T(0.0), T(0.1), T(0.5), T(1.0)}; +void test_hermite(T abs_tol, T rel_tol) { + test_NaN_propagation(); - for (T x : Samples) { - testHermiteNotNaN(x); - testHermiteAnalytic(x, AbsTolerance, RelTolerance); + for (T x : sample_points()) { + test_not_NaN(x); + test_analytic_solution(x, abs_tol, rel_tol); } } template -void testHermiteByInteger() { - const unsigned nMax = 128; - for (unsigned n = 0; n < nMax; ++n) +void test_integers() { + for (unsigned n = 0; n < MAX_N; ++n) for (Integer x : {-1, 0, 1}) assert(std::hermite(n, x) == std::hermite(n, static_cast(x))); } -void testHermiteF() { - const unsigned nMax = 128; - const std::array samples{-1.0f, -0.5f, -0.1f, 0.0f, 0.1f, 0.5f, 1.0f}; - - for (unsigned n = 0; n < nMax; ++n) - for (float x : samples) +void test_hermitef() { + for (unsigned n = 0; n < MAX_N; ++n) + for (float x : sample_points()) assert(std::hermite(n, x) == std::hermitef(n, x)); } -void testHermiteL() { - const unsigned nMax = 128; - const std::array samples{-1.0l, -0.5l, -0.1l, 0.0l, 0.1l, 0.5l, 1.0l}; - - for (unsigned n = 0; n < nMax; ++n) - for (long double x : samples) +void test_hermitel() { + for (unsigned n = 0; n < MAX_N; ++n) + for (long double x : sample_points()) assert(std::hermite(n, x) == std::hermitel(n, x)); } } // namespace int main(int, char**) { - testHermite(1e-5f, 1e-5f); - testHermite(1e-11, 1e-11); - testHermite(1e-12l, 1e-12l); + test_hermite(1e-5f, 1e-5f); + test_hermite(1e-11, 1e-11); + test_hermite(1e-12l, 1e-12l); - testHermiteF(); - testHermiteL(); + test_hermitef(); + test_hermitel(); - testRecurrenceRelation(1e-5f, 1e-5f); - testRecurrenceRelation(1e-11, 1e-11); - testRecurrenceRelation(1e-12l, 1e-12l); + test_recurrence_relation(1e-5f, 1e-5f); + test_recurrence_relation(1e-11, 1e-11); + test_recurrence_relation(1e-12l, 1e-12l); - testHermiteRoots(1e-5f); - testHermiteRoots(1e-9); - testHermiteRoots(1e-10l); + test_roots(1e-5f); + test_roots(1e-9); + test_roots(1e-10l); - testHermiteByInteger(); - testHermiteByInteger(); - testHermiteByInteger(); - testHermiteByInteger(); + test_integers(); + test_integers(); + test_integers(); + test_integers(); return 0; } From 778d8ffbb05bf4a724d747dac10ac917fc8669b2 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:10 +0200 Subject: [PATCH 44/80] status page --- libcxx/docs/Status/SpecialMath.rst | 37 ++++++++++++++++++++++ libcxx/docs/Status/SpecialMathPapers.csv | 2 ++ libcxx/docs/Status/SpecialMathProjects.csv | 22 +++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 libcxx/docs/Status/SpecialMath.rst create mode 100644 libcxx/docs/Status/SpecialMathPapers.csv create mode 100644 libcxx/docs/Status/SpecialMathProjects.csv diff --git a/libcxx/docs/Status/SpecialMath.rst b/libcxx/docs/Status/SpecialMath.rst new file mode 100644 index 0000000000000..28045f3290fdd --- /dev/null +++ b/libcxx/docs/Status/SpecialMath.rst @@ -0,0 +1,37 @@ +.. special-math-status: + +====================================================== +libc++ Mathematical Special Functions Status (P0226R1) +====================================================== + +.. include:: ../Helpers/Styles.rst + +.. contents:: + :local: + +Overview +======== + +This document contains the status of the C++17 mathematical special functions implementation in libc++. +It is used to track both the status of the sub-projects of the effort and who is assigned to these sub-projects. +This avoids duplicating effort. + +If you are interested in contributing to this effort, please send a message +to the #libcxx channel in the LLVM discord. Please *do not* start working +on any items below that has already been assigned to someone else. + +Sub-projects in the Implementation Effort +========================================= + +.. csv-table:: + :file: SpecialMathProjects.csv + :header-rows: 1 + :widths: auto + +Paper and Issue Status +====================== + +.. csv-table:: + :file: SpecialMathPapers.csv + :header-rows: 1 + :widths: auto diff --git a/libcxx/docs/Status/SpecialMathPapers.csv b/libcxx/docs/Status/SpecialMathPapers.csv new file mode 100644 index 0000000000000..be00c63e6fe3f --- /dev/null +++ b/libcxx/docs/Status/SpecialMathPapers.csv @@ -0,0 +1,2 @@ +Number,Name,Standard,Assignee,Status,First released version +`P0226 `_,"Mathematical Special Functions for C++17","C++17",,"|In Progress|" diff --git a/libcxx/docs/Status/SpecialMathProjects.csv b/libcxx/docs/Status/SpecialMathProjects.csv new file mode 100644 index 0000000000000..57be6c746c590 --- /dev/null +++ b/libcxx/docs/Status/SpecialMathProjects.csv @@ -0,0 +1,22 @@ +Section,Description,Assignee,Complete +| `[sf.cmath.assoc.laguerre] `_, std::assoc_laguerre, None, |Not Started| +| `[sf.cmath.assoc.legendre] `_, std::assoc_legendre, None, |Not Started| +| `[sf.cmath.beta] `_, std::beta, None, |Not Started| +| `[sf.cmath.comp.ellint.1] `_, std::comp_ellint_1, None, |Not Started| +| `[sf.cmath.comp.ellint.2] `_, std::comp_ellint_2, None, |Not Started| +| `[sf.cmath.comp.ellint.3] `_, std::comp_ellint_3, None, |Not Started| +| `[sf.cmath.cyl.bessel.i] `_, std::cyl_bessel_i, None, |Not Started| +| `[sf.cmath.cyl.bessel.j] `_, std::cyl_bessel_j, None, |Not Started| +| `[sf.cmath.cyl.bessel.k] `_, std::cyl_bessel_k, None, |Not Started| +| `[sf.cmath.cyl.neumann] `_, std::cyl_neumann, None, |Not Started| +| `[sf.cmath.ellint.1] `_, std::ellint_1, None, |Not Started| +| `[sf.cmath.ellint.2] `_, std::ellint_2, None, |Not Started| +| `[sf.cmath.ellint.3] `_, std::ellint_3, None, |Not Started| +| `[sf.cmath.expint] `_, std::expint, None, |Not Started| +| `[sf.cmath.hermite] `_, std::hermite, None, |Complete| +| `[sf.cmath.laguerre] `_, std::laguerre, None, |Not Started| +| `[sf.cmath.legendre] `_, std::legendre, None, |Not Started| +| `[sf.cmath.riemann.zeta] `_, std::riemann_zeta, None, |Not Started| +| `[sf.cmath.sph.bessel] `_, std::sph_bessel, None, |Not Started| +| `[sf.cmath.sph.legendre] `_, std::sph_legendre, None, |Not Started| +| `[sf.cmath.sph.neumann] `_, std::sph_neumann, None, |Not Started| From 7a329b98113bcc7d16ac2b637a829ae377bb957d Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:10 +0200 Subject: [PATCH 45/80] remove dead code: lit header comments --- libcxx/utils/libcxx/header_information.py | 1 - 1 file changed, 1 deletion(-) diff --git a/libcxx/utils/libcxx/header_information.py b/libcxx/utils/libcxx/header_information.py index 25fadadfb1d0a..166c9a77c08e7 100644 --- a/libcxx/utils/libcxx/header_information.py +++ b/libcxx/utils/libcxx/header_information.py @@ -56,7 +56,6 @@ "cwchar": "// UNSUPPORTED: no-wide-characters", "cwctype": "// UNSUPPORTED: no-wide-characters", "experimental/iterator": "// UNSUPPORTED: c++03", - "experimental/math": "// UNSUPPORTED: c++03, c++11, c++14", "experimental/propagate_const": "// UNSUPPORTED: c++03", "experimental/simd": "// UNSUPPORTED: c++03", "experimental/type_traits": "// UNSUPPORTED: c++03", From 1bc981b8798ad45b58602e4ecb9009c3364c2349 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:11 +0200 Subject: [PATCH 46/80] remove comment about integer->double conversion --- libcxx/include/cmath | 1 - 1 file changed, 1 deletion(-) diff --git a/libcxx/include/cmath b/libcxx/include/cmath index 35b603ded5f45..f4c739175e23d 100644 --- a/libcxx/include/cmath +++ b/libcxx/include/cmath @@ -809,7 +809,6 @@ inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __n, long double __x) template _LIBCPP_HIDE_FROM_ABI std::enable_if_t, double> hermite(unsigned int __n, _Integer __x) { - // use double internally -- see C++17 standard - 29.9.1.2.2 return std::hermite(__n, static_cast(__x)); } #endif // _LIBCPP_STD_VER >= 17 From d8e41c8a7c309dbe03bac2c268a13ecb264236dd Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:11 +0200 Subject: [PATCH 47/80] specify implementation-defined behavior: hermite(n,x) for n>=128 --- libcxx/docs/ImplementationDefinedBehavior.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libcxx/docs/ImplementationDefinedBehavior.rst b/libcxx/docs/ImplementationDefinedBehavior.rst index 3000bb7cfa468..f0ef733fc2c55 100644 --- a/libcxx/docs/ImplementationDefinedBehavior.rst +++ b/libcxx/docs/ImplementationDefinedBehavior.rst @@ -51,6 +51,17 @@ Libc++ determines that a stream is Unicode-capable terminal by: `_. This function is used for other ``std::print`` overloads that don't take an ``ostream&`` argument. +`[sf.cmath] `_ Mathematical Special Functions: Large indices +---------------------------------------------------------------------------------------- + +Most functions within the Mathematical Special Functions section contain integral indices. +The Standard specifies the result for larger indices as implementation-defined. +Libc++ pursuits reasonable results by choosing the same formulas as for indices below that threshold. +E.g. + +- ``std::hermite(unsigned n, T x)`` for ``n >= 128`` + + Listed in the index of implementation-defined behavior ====================================================== From df553a6dd1a7ec3f489b5f47d58bcda4938161ad Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:11 +0200 Subject: [PATCH 48/80] hermite(unsigned, _Integer): changed SFINAE usage --- libcxx/include/cmath | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/include/cmath b/libcxx/include/cmath index f4c739175e23d..2d2cb5ae39589 100644 --- a/libcxx/include/cmath +++ b/libcxx/include/cmath @@ -807,8 +807,8 @@ inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __n, float __x) { return st inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __n, long double __x) { return std::hermite(__n, __x); } -template -_LIBCPP_HIDE_FROM_ABI std::enable_if_t, double> hermite(unsigned int __n, _Integer __x) { +template , int> = 0> +_LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, _Integer __x) { return std::hermite(__n, static_cast(__x)); } #endif // _LIBCPP_STD_VER >= 17 From 9f116230161f60ad0b4f38065a254940bc73a396 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:12 +0200 Subject: [PATCH 49/80] link status page from general C++17 status page --- libcxx/docs/Status/Cxx17.rst | 1 + libcxx/docs/Status/Cxx17Papers.csv | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libcxx/docs/Status/Cxx17.rst b/libcxx/docs/Status/Cxx17.rst index d4426afa81638..ad4f8576f03db 100644 --- a/libcxx/docs/Status/Cxx17.rst +++ b/libcxx/docs/Status/Cxx17.rst @@ -41,6 +41,7 @@ Paper Status .. note:: .. [#note-P0067] P0067: ``std::(to|from)_chars`` for integrals has been available since version 7.0. ``std::to_chars`` for ``float`` and ``double`` since version 14.0 ``std::to_chars`` for ``long double`` uses the implementation for ``double``. + .. [#note-P0226] P0226: Progress is tracked `here `_. .. [#note-P0607] P0607: The parts of P0607 that are not done are the ```` bits. .. [#note-P0154] P0154: The required macros are only implemented as of clang 19. .. [#note-P0452] P0452: The changes to ``std::transform_inclusive_scan`` and ``std::transform_exclusive_scan`` have not yet been implemented. diff --git a/libcxx/docs/Status/Cxx17Papers.csv b/libcxx/docs/Status/Cxx17Papers.csv index aab710ce785ff..6c657d51f5c7e 100644 --- a/libcxx/docs/Status/Cxx17Papers.csv +++ b/libcxx/docs/Status/Cxx17Papers.csv @@ -26,7 +26,7 @@ "`P0013R1 `__","LWG","Logical type traits rev 2","Kona","|Complete|","3.8" "","","","","","" "`P0024R2 `__","LWG","The Parallelism TS Should be Standardized","Jacksonville","|Partial|","" -"`P0226R1 `__","LWG","Mathematical Special Functions for C++17","Jacksonville","|In Progress|","" +"`P0226R1 `__","LWG","Mathematical Special Functions for C++17","Jacksonville","|In Progress| [#note-P0226]_","" "`P0220R1 `__","LWG","Adopt Library Fundamentals V1 TS Components for C++17","Jacksonville","|Complete|","16.0" "`P0218R1 `__","LWG","Adopt the File System TS for C++17","Jacksonville","|Complete|","7.0" "`P0033R1 `__","LWG","Re-enabling shared_from_this","Jacksonville","|Complete|","3.9" From d5b4b4937b2fd0c16890b0e81dd3c2ebf1bac557 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:12 +0200 Subject: [PATCH 50/80] move implementation from include/cmath to include/__math/special_functions.h --- libcxx/include/CMakeLists.txt | 1 + libcxx/include/__math/special_functions.h | 74 +++++++++++++++++++++++ libcxx/include/cmath | 49 +-------------- libcxx/include/module.modulemap | 1 + 4 files changed, 77 insertions(+), 48 deletions(-) create mode 100644 libcxx/include/__math/special_functions.h diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 07dd25604a9c7..55956b9ed2644 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -508,6 +508,7 @@ set(files __math/remainder.h __math/roots.h __math/rounding_functions.h + __math/special_functions.h __math/traits.h __math/trigonometric_functions.h __mbstate_t.h diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h new file mode 100644 index 0000000000000..ee82a76940e4b --- /dev/null +++ b/libcxx/include/__math/special_functions.h @@ -0,0 +1,74 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_SPECIAL_FUNCTIONS_H +#define _LIBCPP___MATH_SPECIAL_FUNCTIONS_H + +#include <__config> +#include <__math/traits.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_integral.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 + +/// \return the Hermite polynomial \f$ H_n(x) \f$ +/// \note The implementation is based on the recurrence formula +/// \f[ +/// H_{n+1}(x) = 2x H_n(x) - 2n H_{n-1} +/// \f] +/// Press, William H., et al. Numerical recipes 3rd edition: The art of +/// scientific computing. Cambridge university press, 2007, p. 183. +template +_LIBCPP_HIDE_FROM_ABI _Real __hermite(unsigned __n, _Real __x) { + if (__math::isnan(__x)) + return std::numeric_limits<_Real>::quiet_NaN(); + + _Real __H_0{1}; + if (__n == 0) + return __H_0; + + _Real __H_n_prev = __H_0; + _Real __H_n = 2 * __x; + for (unsigned __i = 1; __i < __n; ++__i) { + _Real __H_n_next = 2 * (__x * __H_n - __i * __H_n_prev); + __H_n_prev = __H_n; + __H_n = __H_n_next; + } + return __H_n; +} + +inline _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, double __x) { return std::__hermite(__n, __x); } + +inline _LIBCPP_HIDE_FROM_ABI float hermite(unsigned __n, float __x) { + // use double internally -- float is too prone to overflow! + return static_cast(std::hermite(__n, static_cast(__x))); +} + +inline _LIBCPP_HIDE_FROM_ABI long double hermite(unsigned __n, long double __x) { return std::__hermite(__n, __x); } + +inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __n, float __x) { return std::hermite(__n, __x); } + +inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __n, long double __x) { return std::hermite(__n, __x); } + +template , int> = 0> +_LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, _Integer __x) { + return std::hermite(__n, static_cast(__x)); +} +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_SPECIAL_FUNCTIONS_H diff --git a/libcxx/include/cmath b/libcxx/include/cmath index 2d2cb5ae39589..471f0655553f5 100644 --- a/libcxx/include/cmath +++ b/libcxx/include/cmath @@ -309,13 +309,13 @@ constexpr long double lerp(long double a, long double b, long double t) noexcept #include <__type_traits/is_arithmetic.h> #include <__type_traits/is_constant_evaluated.h> #include <__type_traits/is_floating_point.h> -#include <__type_traits/is_integral.h> #include <__type_traits/is_same.h> #include <__type_traits/promote.h> #include <__type_traits/remove_cv.h> #include #include +#include <__math/special_functions.h> #include #ifndef _LIBCPP_MATH_H @@ -766,53 +766,6 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp __constexpr_scalbn(_Tp _ return __builtin_scalbn(__x, __exp); } -#if _LIBCPP_STD_VER >= 17 - -/// \return the Hermite polynomial \f$ H_n(x) \f$ -/// \note The implementation is based on the recurrence formula -/// \f[ -/// H_{n+1}(x) = 2x H_n(x) - 2n H_{n-1} -/// \f] -/// Press, William H., et al. Numerical recipes 3rd edition: The art of -/// scientific computing. Cambridge university press, 2007, p. 183. -template -_LIBCPP_HIDE_FROM_ABI _Real __hermite(unsigned __n, _Real __x) { - if (std::isnan(__x)) - return std::numeric_limits<_Real>::quiet_NaN(); - - _Real __H_0{1}; - if (__n == 0) - return __H_0; - - _Real __H_n_prev = __H_0; - _Real __H_n = 2 * __x; - for (unsigned __i = 1; __i < __n; ++__i) { - _Real __H_n_next = 2 * (__x * __H_n - __i * __H_n_prev); - __H_n_prev = __H_n; - __H_n = __H_n_next; - } - return __H_n; -} - -inline _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, double __x) { return std::__hermite(__n, __x); } - -inline _LIBCPP_HIDE_FROM_ABI float hermite(unsigned __n, float __x) { - // use double internally -- float is too prone to overflow! - return static_cast(std::hermite(__n, static_cast(__x))); -} - -inline _LIBCPP_HIDE_FROM_ABI long double hermite(unsigned __n, long double __x) { return std::__hermite(__n, __x); } - -inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __n, float __x) { return std::hermite(__n, __x); } - -inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __n, long double __x) { return std::hermite(__n, __x); } - -template , int> = 0> -_LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, _Integer __x) { - return std::hermite(__n, static_cast(__x)); -} -#endif // _LIBCPP_STD_VER >= 17 - #if _LIBCPP_STD_VER >= 20 template _LIBCPP_HIDE_FROM_ABI constexpr _Fp __lerp(_Fp __a, _Fp __b, _Fp __t) noexcept { diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 4ad506781c489..249c138012a3e 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1480,6 +1480,7 @@ module std_private_math_modulo [system] { header "__mat module std_private_math_remainder [system] { header "__math/remainder.h" } module std_private_math_roots [system] { header "__math/roots.h" } module std_private_math_rounding_functions [system] { header "__math/rounding_functions.h" } +module std_private_math_special_functions [system] { header "__math/special_functions.h" } module std_private_math_traits [system] { header "__math/traits.h" } module std_private_math_trigonometric_functions [system] { header "__math/trigonometric_functions.h" } From f77fd3cb07d563b671a04eb74fdd9229db8c6756 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:12 +0200 Subject: [PATCH 51/80] simplify NaN handling (no conversion) --- libcxx/include/__math/special_functions.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h index ee82a76940e4b..ac2c69c3df85b 100644 --- a/libcxx/include/__math/special_functions.h +++ b/libcxx/include/__math/special_functions.h @@ -14,7 +14,6 @@ #include <__math/traits.h> #include <__type_traits/enable_if.h> #include <__type_traits/is_integral.h> -#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -34,7 +33,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD template _LIBCPP_HIDE_FROM_ABI _Real __hermite(unsigned __n, _Real __x) { if (__math::isnan(__x)) - return std::numeric_limits<_Real>::quiet_NaN(); + return __x; _Real __H_0{1}; if (__n == 0) From 68cee2f783b3106af841ed0f4f869db0d67bd9bb Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:13 +0200 Subject: [PATCH 52/80] simplify status documentation: single paper needs no table --- libcxx/docs/Status/SpecialMath.rst | 8 +++----- libcxx/docs/Status/SpecialMathPapers.csv | 2 -- 2 files changed, 3 insertions(+), 7 deletions(-) delete mode 100644 libcxx/docs/Status/SpecialMathPapers.csv diff --git a/libcxx/docs/Status/SpecialMath.rst b/libcxx/docs/Status/SpecialMath.rst index 28045f3290fdd..fcc9f03e3ae64 100644 --- a/libcxx/docs/Status/SpecialMath.rst +++ b/libcxx/docs/Status/SpecialMath.rst @@ -13,7 +13,7 @@ Overview ======== This document contains the status of the C++17 mathematical special functions implementation in libc++. -It is used to track both the status of the sub-projects of the effort and who is assigned to these sub-projects. +It is used to track both the status of the sub-projects of the effort and who is assigned to these sub-projects. This avoids duplicating effort. If you are interested in contributing to this effort, please send a message @@ -31,7 +31,5 @@ Sub-projects in the Implementation Effort Paper and Issue Status ====================== -.. csv-table:: - :file: SpecialMathPapers.csv - :header-rows: 1 - :widths: auto +The underlying paper is `Mathematical Special Functions for C++17 (P0226) `_ and is included in C++17. +Implementation is *In Progress*. diff --git a/libcxx/docs/Status/SpecialMathPapers.csv b/libcxx/docs/Status/SpecialMathPapers.csv deleted file mode 100644 index be00c63e6fe3f..0000000000000 --- a/libcxx/docs/Status/SpecialMathPapers.csv +++ /dev/null @@ -1,2 +0,0 @@ -Number,Name,Standard,Assignee,Status,First released version -`P0226 `_,"Mathematical Special Functions for C++17","C++17",,"|In Progress|" From 68eef2926bdd0946ba8d60baa465d8618860b6f6 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:13 +0200 Subject: [PATCH 53/80] assign std::hermite to myself --- libcxx/docs/Status/SpecialMathProjects.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/docs/Status/SpecialMathProjects.csv b/libcxx/docs/Status/SpecialMathProjects.csv index 57be6c746c590..f964e79de91d3 100644 --- a/libcxx/docs/Status/SpecialMathProjects.csv +++ b/libcxx/docs/Status/SpecialMathProjects.csv @@ -13,7 +13,7 @@ Section,Description,Assignee,Complete | `[sf.cmath.ellint.2] `_, std::ellint_2, None, |Not Started| | `[sf.cmath.ellint.3] `_, std::ellint_3, None, |Not Started| | `[sf.cmath.expint] `_, std::expint, None, |Not Started| -| `[sf.cmath.hermite] `_, std::hermite, None, |Complete| +| `[sf.cmath.hermite] `_, std::hermite, Paul Xi Cao, |Complete| | `[sf.cmath.laguerre] `_, std::laguerre, None, |Not Started| | `[sf.cmath.legendre] `_, std::legendre, None, |Not Started| | `[sf.cmath.riemann.zeta] `_, std::riemann_zeta, None, |Not Started| From 379b6df386c984d9c1b911e45a545fba01190904 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:13 +0200 Subject: [PATCH 54/80] remove anonymous namespace in test file --- libcxx/test/std/numerics/c.math/hermite.pass.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp index 397046219bb1f..8f40839b0c663 100644 --- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp +++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp @@ -16,8 +16,6 @@ #include -namespace { - inline constexpr unsigned MAX_N = 128; template @@ -283,7 +281,6 @@ void test_hermitel() { for (long double x : sample_points()) assert(std::hermite(n, x) == std::hermitel(n, x)); } -} // namespace int main(int, char**) { test_hermite(1e-5f, 1e-5f); From c0f15bf9a424572a7f8bd35c3eaeb5b045398736 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:14 +0200 Subject: [PATCH 55/80] test: add synopsis --- libcxx/test/std/numerics/c.math/hermite.pass.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp index 8f40839b0c663..b026f48a8267c 100644 --- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp +++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp @@ -7,6 +7,16 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14 +// + +// Tests std::hermite and its related functions: +// double hermite( unsigned n, double x); +// float hermite( unsigned n, float x); +// long double hermite( unsigned n, long double x); +// float hermitef(unsigned n, float x); +// long double hermitel(unsigned n, long double x); +// template +// double hermite( unsigned n, Integer x); #include #include From aaf8364c61dadb739b62b00404ce9b438dbc824b Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:14 +0200 Subject: [PATCH 56/80] test: remove unused include --- libcxx/test/std/numerics/c.math/hermite.pass.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp index b026f48a8267c..08500aaa56579 100644 --- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp +++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp @@ -24,8 +24,6 @@ #include #include -#include - inline constexpr unsigned MAX_N = 128; template From c264badaf13e677235a6b24d100cdbb6b1fdb9c8 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:14 +0200 Subject: [PATCH 57/80] test: sort includes --- libcxx/test/std/numerics/c.math/hermite.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp index 08500aaa56579..e10cb3b76475a 100644 --- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp +++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp @@ -18,11 +18,11 @@ // template // double hermite( unsigned n, Integer x); +#include #include #include #include #include -#include inline constexpr unsigned MAX_N = 128; From 097d62269332ef4b6e9dc57259883c4d1f11771b Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:15 +0200 Subject: [PATCH 58/80] test: refactor/style change. only test() within main() --- .../test/std/numerics/c.math/hermite.pass.cpp | 226 +++++++++--------- 1 file changed, 109 insertions(+), 117 deletions(-) diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp index e10cb3b76475a..7b178b009c8d6 100644 --- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp +++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp @@ -31,82 +31,38 @@ std::array sample_points() { return {-1.0, -0.5, -0.1, 0.0, 0.1, 0.5, 1.0}; } -template -void test_NaN_propagation() { - T NaN = std::numeric_limits::quiet_NaN(); - for (unsigned n = 0; n < MAX_N; ++n) - assert(std::isnan(std::hermite(n, NaN))); -} - -template -void test_not_NaN(T x) { - assert(!std::isnan(x)); - for (unsigned n = 0; n < MAX_N; ++n) - assert(!std::isnan(std::hermite(n, x))); -} - -template -struct CompareFloatingValues { - T abs_tol; - T rel_tol; +template +class CompareFloatingValues { +private: + Real abs_tol; + Real rel_tol; + +public: + CompareFloatingValues() { + abs_tol = []() -> Real { + if (std::is_same_v) + return 1e-5f; + else if (std::is_same_v) + return 1e-11; + else + return 1e-12l; + }(); + + rel_tol = abs_tol; + } - bool operator()(T result, T expected) const { + bool operator()(Real result, Real expected) const { if (std::isinf(expected) && std::isinf(result)) - return true; + return result == expected; if (std::isnan(expected) || std::isnan(result)) return false; - T tol = abs_tol + std::abs(expected) * rel_tol; + Real tol = abs_tol + std::abs(expected) * rel_tol; return std::abs(result - expected) < tol; } }; -template -void test_analytic_solution(T x, T abs_tol, T rel_tol) { - assert(!std::isnan(x)); - - const auto h0 = [](T) -> T { return 1; }; - const auto h1 = [](T y) -> T { return 2 * y; }; - const auto h2 = [](T y) -> T { return 4 * y * y - 2; }; - const auto h3 = [](T y) -> T { return y * (8 * y * y - 12); }; - const auto h4 = [](T y) -> T { return (16 * std::pow(y, 4) - 48 * y * y + 12); }; - const auto h5 = [](T y) -> T { return y * (32 * std::pow(y, 4) - 160 * y * y + 120); }; - - const CompareFloatingValues compare{.abs_tol = abs_tol, .rel_tol = rel_tol}; - assert(compare(std::hermite(0, x), h0(x))); - assert(compare(std::hermite(1, x), h1(x))); - assert(compare(std::hermite(2, x), h2(x))); - assert(compare(std::hermite(3, x), h3(x))); - assert(compare(std::hermite(4, x), h4(x))); - assert(compare(std::hermite(5, x), h5(x))); -} - -/// \details This method checks if the following recurrence relation holds: -/// \f[ -/// H_{n+1}(x) = 2x H_n(x) - 2n H_{n-1}(x) -/// \f] -template -void test_recurrence_relation(T x, T abs_tol, T rel_tol) { - assert(!std::isnan(x)); - - const CompareFloatingValues compare{.abs_tol = abs_tol, .rel_tol = rel_tol}; - for (unsigned n = 1; n < MAX_N - 1; ++n) { - T H_next = std::hermite(n + 1, x); - T H_next_recurrence = 2 * (x * std::hermite(n, x) - n * std::hermite(n - 1, x)); - - if (std::isinf(H_next)) - break; - assert(compare(H_next, H_next_recurrence)); - } -} - -template -void test_recurrence_relation(T abs_tol, T rel_tol) { - for (T x : sample_points()) - test_recurrence_relation(x, abs_tol, rel_tol); -} - /// \note Roots are taken from /// Salzer, Herbert E., Ruth Zucker, and Ruth Capuano. /// Table of the zeros and weight factors of the first twenty Hermite @@ -242,74 +198,110 @@ std::vector get_roots(unsigned n) { } } -/// \param [in] Tolerance of the root. This value must be smaller than -/// the smallest difference between adjacent roots in the given range -/// with n <= 20. -template -void test_roots(T Tolerance) { - const auto is_sign_change = [Tolerance](unsigned n, T x) -> bool { - return std::hermite(n, x - Tolerance) * std::hermite(n, x + Tolerance) < 0; - }; - - for (unsigned n = 0; n <= 20u; ++n) { - for (T x : get_roots(n)) { - // the roots are symmetric: if x is a root, so is -x - if (x > 0) - assert(is_sign_change(n, -x)); - assert(is_sign_change(n, x)); +template +void test() { + { // checks if NaNs are reported correctly (i.e. output == input for input == NaN) + using nl = std::numeric_limits; + for (Real NaN : {nl::quiet_NaN(), nl::signaling_NaN()}) + for (unsigned n = 0; n < MAX_N; ++n) + assert(std::isnan(std::hermite(n, NaN))); + } + + { // simple sample points for n=0..127 should not produce NaNs. + for (Real x : sample_points()) + for (unsigned n = 0; n < MAX_N; ++n) + assert(!std::isnan(std::hermite(n, x))); + } + + { // checks std::hermite(n, x) for n=0..5 against analytic polynoms + const auto h0 = [](Real) -> Real { return 1; }; + const auto h1 = [](Real y) -> Real { return 2 * y; }; + const auto h2 = [](Real y) -> Real { return 4 * y * y - 2; }; + const auto h3 = [](Real y) -> Real { return y * (8 * y * y - 12); }; + const auto h4 = [](Real y) -> Real { return (16 * std::pow(y, 4) - 48 * y * y + 12); }; + const auto h5 = [](Real y) -> Real { return y * (32 * std::pow(y, 4) - 160 * y * y + 120); }; + + for (Real x : sample_points()) { + const CompareFloatingValues compare; + assert(compare(std::hermite(0, x), h0(x))); + assert(compare(std::hermite(1, x), h1(x))); + assert(compare(std::hermite(2, x), h2(x))); + assert(compare(std::hermite(3, x), h3(x))); + assert(compare(std::hermite(4, x), h4(x))); + assert(compare(std::hermite(5, x), h5(x))); } } -} -template -void test_hermite(T abs_tol, T rel_tol) { - test_NaN_propagation(); + { // checks std::hermitef for bitwise equality with std::hermite(unsigned, float) + if constexpr (std::is_same_v) + for (unsigned n = 0; n < MAX_N; ++n) + for (float x : sample_points()) + assert(std::hermite(n, x) == std::hermitef(n, x)); + } + + { // checks std::hermitel for bitwise equality with std::hermite(unsigned, long double) + if constexpr (std::is_same_v) + for (unsigned n = 0; n < MAX_N; ++n) + for (long double x : sample_points()) + assert(std::hermite(n, x) == std::hermitel(n, x)); + } - for (T x : sample_points()) { - test_not_NaN(x); - test_analytic_solution(x, abs_tol, rel_tol); + { // Checks if the characteristic recurrence relation holds: H_{n+1}(x) = 2x H_n(x) - 2n H_{n-1}(x) + for (Real x : sample_points()) { + for (unsigned n = 1; n < MAX_N - 1; ++n) { + Real H_next = std::hermite(n + 1, x); + Real H_next_recurrence = 2 * (x * std::hermite(n, x) - n * std::hermite(n - 1, x)); + + if (std::isinf(H_next)) + break; + const CompareFloatingValues compare; + assert(compare(H_next, H_next_recurrence)); + } + } + } + + { // sanity checks: hermite polynoms need to change signs at (simple) roots. checked upto order n<=20. + + // root tolerance: must be smaller than the smallest difference between adjacent roots + Real tol = []() -> Real { + if (std::is_same_v) + return 1e-5f; + else if (std::is_same_v) + return 1e-9; + else + return 1e-10l; + }(); + + const auto is_sign_change = [tol](unsigned n, Real x) -> bool { + return std::hermite(n, x - tol) * std::hermite(n, x + tol) < 0; + }; + + for (unsigned n = 0; n <= 20u; ++n) { + for (Real x : get_roots(n)) { + // the roots are symmetric: if x is a root, so is -x + if (x > 0) + assert(is_sign_change(n, -x)); + assert(is_sign_change(n, x)); + } + } } } template void test_integers() { + // checks that std::hermite(unsigned, Integer) actually wraps std::hermite(unsigned, double) for (unsigned n = 0; n < MAX_N; ++n) for (Integer x : {-1, 0, 1}) assert(std::hermite(n, x) == std::hermite(n, static_cast(x))); } -void test_hermitef() { - for (unsigned n = 0; n < MAX_N; ++n) - for (float x : sample_points()) - assert(std::hermite(n, x) == std::hermitef(n, x)); -} - -void test_hermitel() { - for (unsigned n = 0; n < MAX_N; ++n) - for (long double x : sample_points()) - assert(std::hermite(n, x) == std::hermitel(n, x)); -} - -int main(int, char**) { - test_hermite(1e-5f, 1e-5f); - test_hermite(1e-11, 1e-11); - test_hermite(1e-12l, 1e-12l); - - test_hermitef(); - test_hermitel(); - - test_recurrence_relation(1e-5f, 1e-5f); - test_recurrence_relation(1e-11, 1e-11); - test_recurrence_relation(1e-12l, 1e-12l); - - test_roots(1e-5f); - test_roots(1e-9); - test_roots(1e-10l); +int main() { + test(); + test(); + test(); test_integers(); test_integers(); test_integers(); test_integers(); - - return 0; } From b5cee48491d0a1293dc6a11b0334d42d05eb7ab1 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:15 +0200 Subject: [PATCH 59/80] test: make use of types::for_each --- .../test/std/numerics/c.math/hermite.pass.cpp | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp index 7b178b009c8d6..5a740af7ae0e9 100644 --- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp +++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp @@ -24,6 +24,8 @@ #include #include +#include "type_algorithms.h" + inline constexpr unsigned MAX_N = 128; template @@ -287,21 +289,24 @@ void test() { } } -template -void test_integers() { - // checks that std::hermite(unsigned, Integer) actually wraps std::hermite(unsigned, double) - for (unsigned n = 0; n < MAX_N; ++n) - for (Integer x : {-1, 0, 1}) - assert(std::hermite(n, x) == std::hermite(n, static_cast(x))); -} +struct TestFloat { + template + void operator()() { + test(); + } +}; + +struct TestInt { + template + void operator()() { + // checks that std::hermite(unsigned, Integer) actually wraps std::hermite(unsigned, double) + for (unsigned n = 0; n < MAX_N; ++n) + for (Integer x : {-1, 0, 1}) + assert(std::hermite(n, x) == std::hermite(n, static_cast(x))); + } +}; int main() { - test(); - test(); - test(); - - test_integers(); - test_integers(); - test_integers(); - test_integers(); + types::for_each(types::floating_point_types(), TestFloat()); + types::for_each(types::type_list(), TestInt()); } From 22752010ff1e76d72d514229a1242b2c5f799b41 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:15 +0200 Subject: [PATCH 60/80] test: replace exception throwing by assert --- libcxx/test/std/numerics/c.math/hermite.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp index 5a740af7ae0e9..32d538eee42c3 100644 --- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp +++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp @@ -196,7 +196,7 @@ std::vector get_roots(unsigned n) { T(5.3874808900112)}; default: - throw "Roots of Hermite polynomial of order " + std::to_string(n) + " not implemented!\n"; + assert(0); } } From d69176d6960160fd1104ade50d37b3662458e07e Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:16 +0200 Subject: [PATCH 61/80] test: additional sample points with abs(x)>1 --- libcxx/test/std/numerics/c.math/hermite.pass.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp index 32d538eee42c3..5f32158a261f3 100644 --- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp +++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp @@ -29,8 +29,8 @@ inline constexpr unsigned MAX_N = 128; template -std::array sample_points() { - return {-1.0, -0.5, -0.1, 0.0, 0.1, 0.5, 1.0}; +std::array sample_points() { + return {-12.34, -7.42, -1.0, -0.5, -0.1, 0.0, 0.1, 0.5, 1.0, 5.67, 15.67}; } template From 25f6c80d4e61fa7f9ab460d79d3a932060e5e888 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:16 +0200 Subject: [PATCH 62/80] test: checks for x=+-inf as input --- .../test/std/numerics/c.math/hermite.pass.cpp | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp index 5f32158a261f3..f718ff30b1b7d 100644 --- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp +++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp @@ -287,6 +287,27 @@ void test() { } } } + + { // check input infinity is handled correctly + Real inf = std::numeric_limits::infinity(); + for (unsigned n = 1; n < MAX_N; ++n) { + assert(std::hermite(n, +inf) == inf); + assert(std::hermite(n, -inf) == ((n & 1) ? -inf : inf)); + } + } + + { // check: if overflow occurs that it is mapped to the correct infinity + Real inf = std::numeric_limits::infinity(); + for (unsigned n = 0; n < MAX_N; ++n) { + // Q: why x=140? + // A: H_127(140) overflows even 8-byte double + if (Real y = std::hermite(n, Real{140}); !std::isfinite(y)) + assert(y == inf); + + if (Real y = std::hermite(n, Real{-140}); !std::isfinite(y)) + assert(y == ((n & 1) ? -inf : inf)); + } + } } struct TestFloat { From 6cd8c7f2be302141d60786947d3e73a7dab509df Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:16 +0200 Subject: [PATCH 63/80] handle overflows --- libcxx/include/__math/special_functions.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h index ac2c69c3df85b..60ad6e173e417 100644 --- a/libcxx/include/__math/special_functions.h +++ b/libcxx/include/__math/special_functions.h @@ -11,9 +11,11 @@ #define _LIBCPP___MATH_SPECIAL_FUNCTIONS_H #include <__config> +#include <__math/copysign.h> #include <__math/traits.h> #include <__type_traits/enable_if.h> #include <__type_traits/is_integral.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -46,6 +48,14 @@ _LIBCPP_HIDE_FROM_ABI _Real __hermite(unsigned __n, _Real __x) { __H_n_prev = __H_n; __H_n = __H_n_next; } + + if (!__math::isfinite(__H_n)) { + // Overflow occured. Two possible cases: + // n is odd: return infinity of the same sign as x. + // n is even: return +Inf + _Real inf = std::numeric_limits<_Real>::infinity(); + return (__n & 1) ? __math::copysign(inf, __x) : inf; + } return __H_n; } From 965dfb6beef20a99d8f3680446c62fea5dbcb3e2 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:17 +0200 Subject: [PATCH 64/80] index.rst: add special math status page to TOC --- libcxx/docs/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/docs/index.rst b/libcxx/docs/index.rst index 69a9e575cfe7c..4bca3ccc8fa06 100644 --- a/libcxx/docs/index.rst +++ b/libcxx/docs/index.rst @@ -53,6 +53,7 @@ Getting Started with libc++ Status/PSTL Status/Ranges Status/Spaceship + Status/SpecialMath Status/Zip From 44b7b80aae024212c88a5a50b4ed4b57ce0184bc Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:17 +0200 Subject: [PATCH 65/80] cmath.inc: uncomment std::hermite functions --- libcxx/modules/std/cmath.inc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libcxx/modules/std/cmath.inc b/libcxx/modules/std/cmath.inc index a463c1e3ccf86..fe8ac773c9d1c 100644 --- a/libcxx/modules/std/cmath.inc +++ b/libcxx/modules/std/cmath.inc @@ -334,12 +334,14 @@ export namespace std { using std::expint; using std::expintf; using std::expintl; +#endif // [sf.cmath.hermite], Hermite polynomials using std::hermite; using std::hermitef; using std::hermitel; +#if 0 // [sf.cmath.laguerre], Laguerre polynomials using std::laguerre; using std::laguerref; From 932e08471e1be764c36bb91e2c0fe8dab704d576 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:17 +0200 Subject: [PATCH 66/80] cmath: added implemented functions to synopsis --- libcxx/include/cmath | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libcxx/include/cmath b/libcxx/include/cmath index 471f0655553f5..2039e0602de19 100644 --- a/libcxx/include/cmath +++ b/libcxx/include/cmath @@ -204,6 +204,12 @@ floating_point fmin (arithmetic x, arithmetic y); float fminf(float x, float y); long double fminl(long double x, long double y); +double hermite(unsigned n, double x); // C++17 +float hermite(unsigned n, float x); // C++17 +long double hermite(unsigned n, long double x); // C++17 +template +double hermite(unsigned n, Integer x); // C++17 + floating_point hypot (arithmetic x, arithmetic y); float hypotf(float x, float y); long double hypotl(long double x, long double y); From 473f60065077f3fea1846aac1c51b97bb4a656f0 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:18 +0200 Subject: [PATCH 67/80] cmath: add hermite{l,f} to synopsis --- libcxx/include/cmath | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libcxx/include/cmath b/libcxx/include/cmath index 2039e0602de19..70838f69bd8a1 100644 --- a/libcxx/include/cmath +++ b/libcxx/include/cmath @@ -207,6 +207,8 @@ long double fminl(long double x, long double y); double hermite(unsigned n, double x); // C++17 float hermite(unsigned n, float x); // C++17 long double hermite(unsigned n, long double x); // C++17 +float hermitef(unsigned n, float x); // C++17 +long double hermitel(unsigned n, long double x); // C++17 template double hermite(unsigned n, Integer x); // C++17 From 6932143328b6c18f62166af03f683d67f27dda43 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:18 +0200 Subject: [PATCH 68/80] test: format test's synopsis --- libcxx/test/std/numerics/c.math/hermite.pass.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp index f718ff30b1b7d..b3ab7f2d58895 100644 --- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp +++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp @@ -7,16 +7,16 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14 + // -// Tests std::hermite and its related functions: -// double hermite( unsigned n, double x); -// float hermite( unsigned n, float x); -// long double hermite( unsigned n, long double x); -// float hermitef(unsigned n, float x); -// long double hermitel(unsigned n, long double x); -// template -// double hermite( unsigned n, Integer x); +// double hermite(unsigned n, double x); +// float hermite(unsigned n, float x); +// long double hermite(unsigned n, long double x); +// float hermitef(unsigned n, float x); +// long double hermitel(unsigned n, long double x); +// template +// double hermite(unsigned n, Integer x); #include #include From 4af48df88ab5dc406c3f5983b6f5c5311664ed81 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:18 +0200 Subject: [PATCH 69/80] get rid of doxygen-style comments --- libcxx/include/__math/special_functions.h | 13 ++++++------- libcxx/test/std/numerics/c.math/hermite.pass.cpp | 8 ++++---- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h index 60ad6e173e417..7e30e5e750be3 100644 --- a/libcxx/include/__math/special_functions.h +++ b/libcxx/include/__math/special_functions.h @@ -25,15 +25,13 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 17 -/// \return the Hermite polynomial \f$ H_n(x) \f$ -/// \note The implementation is based on the recurrence formula -/// \f[ -/// H_{n+1}(x) = 2x H_n(x) - 2n H_{n-1} -/// \f] -/// Press, William H., et al. Numerical recipes 3rd edition: The art of -/// scientific computing. Cambridge university press, 2007, p. 183. template _LIBCPP_HIDE_FROM_ABI _Real __hermite(unsigned __n, _Real __x) { + // The Hermite polynomial H_n(x). + // The implementation is based on the recurrence formula: H_{n+1}(x) = 2x H_n(x) - 2n H_{n-1}. + // Press, William H., et al. Numerical recipes 3rd edition: The art of scientific computing. + // Cambridge university press, 2007, p. 183. + if (__math::isnan(__x)) return __x; @@ -76,6 +74,7 @@ template , int> = _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, _Integer __x) { return std::hermite(__n, static_cast(__x)); } + #endif // _LIBCPP_STD_VER >= 17 _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp index b3ab7f2d58895..e5d7b42fe28fa 100644 --- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp +++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp @@ -65,10 +65,10 @@ class CompareFloatingValues { } }; -/// \note Roots are taken from -/// Salzer, Herbert E., Ruth Zucker, and Ruth Capuano. -/// Table of the zeros and weight factors of the first twenty Hermite -/// polynomials. US Government Printing Office, 1952. +// Roots are taken from +// Salzer, Herbert E., Ruth Zucker, and Ruth Capuano. +// Table of the zeros and weight factors of the first twenty Hermite +// polynomials. US Government Printing Office, 1952. template std::vector get_roots(unsigned n) { switch (n) { From 875510084a807af6cf7d78c23005ec9eea1c351b Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:19 +0200 Subject: [PATCH 70/80] test: renamed MAX_N to g_max_n --- .../test/std/numerics/c.math/hermite.pass.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp index e5d7b42fe28fa..65aba486085e2 100644 --- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp +++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp @@ -26,7 +26,7 @@ #include "type_algorithms.h" -inline constexpr unsigned MAX_N = 128; +inline constexpr unsigned g_max_n = 128; template std::array sample_points() { @@ -205,13 +205,13 @@ void test() { { // checks if NaNs are reported correctly (i.e. output == input for input == NaN) using nl = std::numeric_limits; for (Real NaN : {nl::quiet_NaN(), nl::signaling_NaN()}) - for (unsigned n = 0; n < MAX_N; ++n) + for (unsigned n = 0; n < g_max_n; ++n) assert(std::isnan(std::hermite(n, NaN))); } { // simple sample points for n=0..127 should not produce NaNs. for (Real x : sample_points()) - for (unsigned n = 0; n < MAX_N; ++n) + for (unsigned n = 0; n < g_max_n; ++n) assert(!std::isnan(std::hermite(n, x))); } @@ -236,21 +236,21 @@ void test() { { // checks std::hermitef for bitwise equality with std::hermite(unsigned, float) if constexpr (std::is_same_v) - for (unsigned n = 0; n < MAX_N; ++n) + for (unsigned n = 0; n < g_max_n; ++n) for (float x : sample_points()) assert(std::hermite(n, x) == std::hermitef(n, x)); } { // checks std::hermitel for bitwise equality with std::hermite(unsigned, long double) if constexpr (std::is_same_v) - for (unsigned n = 0; n < MAX_N; ++n) + for (unsigned n = 0; n < g_max_n; ++n) for (long double x : sample_points()) assert(std::hermite(n, x) == std::hermitel(n, x)); } { // Checks if the characteristic recurrence relation holds: H_{n+1}(x) = 2x H_n(x) - 2n H_{n-1}(x) for (Real x : sample_points()) { - for (unsigned n = 1; n < MAX_N - 1; ++n) { + for (unsigned n = 1; n < g_max_n - 1; ++n) { Real H_next = std::hermite(n + 1, x); Real H_next_recurrence = 2 * (x * std::hermite(n, x) - n * std::hermite(n - 1, x)); @@ -290,7 +290,7 @@ void test() { { // check input infinity is handled correctly Real inf = std::numeric_limits::infinity(); - for (unsigned n = 1; n < MAX_N; ++n) { + for (unsigned n = 1; n < g_max_n; ++n) { assert(std::hermite(n, +inf) == inf); assert(std::hermite(n, -inf) == ((n & 1) ? -inf : inf)); } @@ -298,7 +298,7 @@ void test() { { // check: if overflow occurs that it is mapped to the correct infinity Real inf = std::numeric_limits::infinity(); - for (unsigned n = 0; n < MAX_N; ++n) { + for (unsigned n = 0; n < g_max_n; ++n) { // Q: why x=140? // A: H_127(140) overflows even 8-byte double if (Real y = std::hermite(n, Real{140}); !std::isfinite(y)) @@ -321,7 +321,7 @@ struct TestInt { template void operator()() { // checks that std::hermite(unsigned, Integer) actually wraps std::hermite(unsigned, double) - for (unsigned n = 0; n < MAX_N; ++n) + for (unsigned n = 0; n < g_max_n; ++n) for (Integer x : {-1, 0, 1}) assert(std::hermite(n, x) == std::hermite(n, static_cast(x))); } From 4fe24ae1dd559152bb9497f754672281e7ff0fa0 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:19 +0200 Subject: [PATCH 71/80] test: assert(false) instead of assert(0) --- libcxx/test/std/numerics/c.math/hermite.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp index 65aba486085e2..e8e536801ba42 100644 --- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp +++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp @@ -196,7 +196,7 @@ std::vector get_roots(unsigned n) { T(5.3874808900112)}; default: - assert(0); + assert(false); } } From 34bd1971ca5920a18a77fd7c6d2e62c0fb620362 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:19 +0200 Subject: [PATCH 72/80] test: inf result for finite input --- .../test/std/numerics/c.math/hermite.pass.cpp | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp index e8e536801ba42..59b25038f48e9 100644 --- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp +++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp @@ -297,15 +297,22 @@ void test() { } { // check: if overflow occurs that it is mapped to the correct infinity - Real inf = std::numeric_limits::infinity(); - for (unsigned n = 0; n < g_max_n; ++n) { - // Q: why x=140? - // A: H_127(140) overflows even 8-byte double - if (Real y = std::hermite(n, Real{140}); !std::isfinite(y)) - assert(y == inf); - - if (Real y = std::hermite(n, Real{-140}); !std::isfinite(y)) - assert(y == ((n & 1) ? -inf : inf)); + if constexpr (std::is_same_v) { + // Q: Why only double? + // A: The numeric values (e.g. overflow threshold `n`) below are different for other types. + static_assert(sizeof(double) == 8); + for (unsigned n = 0; n < g_max_n; ++n) { + // Q: Why n=111 and x=300? + // A: Both are chosen s.t. the first overlow occurs for some `n::infinity(); + assert(std::hermite(n, +300.0) == inf); + assert(std::hermite(n, -300.0) == ((n & 1) ? -inf : inf)); + } + } } } } From 4580bf0c13ae17a920afce51b156dad300babad9 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:20 +0200 Subject: [PATCH 73/80] rename to use ugly name: inf -> __inf --- libcxx/include/__math/special_functions.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h index 7e30e5e750be3..ff83b637876ea 100644 --- a/libcxx/include/__math/special_functions.h +++ b/libcxx/include/__math/special_functions.h @@ -51,8 +51,8 @@ _LIBCPP_HIDE_FROM_ABI _Real __hermite(unsigned __n, _Real __x) { // Overflow occured. Two possible cases: // n is odd: return infinity of the same sign as x. // n is even: return +Inf - _Real inf = std::numeric_limits<_Real>::infinity(); - return (__n & 1) ? __math::copysign(inf, __x) : inf; + _Real __inf = std::numeric_limits<_Real>::infinity(); + return (__n & 1) ? __math::copysign(__inf, __x) : __inf; } return __H_n; } From d68145cddc0eae047b4b9b1b8461cc8360a1025c Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:20 +0200 Subject: [PATCH 74/80] silence clang-tidy warning about variable name in math code --- libcxx/include/__math/special_functions.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h index ff83b637876ea..0b1c753a659ad 100644 --- a/libcxx/include/__math/special_functions.h +++ b/libcxx/include/__math/special_functions.h @@ -32,6 +32,7 @@ _LIBCPP_HIDE_FROM_ABI _Real __hermite(unsigned __n, _Real __x) { // Press, William H., et al. Numerical recipes 3rd edition: The art of scientific computing. // Cambridge university press, 2007, p. 183. + // NOLINTBEGIN(readability-identifier-naming) if (__math::isnan(__x)) return __x; @@ -55,6 +56,7 @@ _LIBCPP_HIDE_FROM_ABI _Real __hermite(unsigned __n, _Real __x) { return (__n & 1) ? __math::copysign(__inf, __x) : __inf; } return __H_n; + // NOLINTEND(readability-identifier-naming) } inline _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, double __x) { return std::__hermite(__n, __x); } From 1a660646fef4c5f522df36023db8cdc99add4093 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:20 +0200 Subject: [PATCH 75/80] test: add more values for integeral x --- libcxx/test/std/numerics/c.math/hermite.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp index 59b25038f48e9..6d4aa697434c6 100644 --- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp +++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp @@ -329,7 +329,7 @@ struct TestInt { void operator()() { // checks that std::hermite(unsigned, Integer) actually wraps std::hermite(unsigned, double) for (unsigned n = 0; n < g_max_n; ++n) - for (Integer x : {-1, 0, 1}) + for (Integer x : {-42, -7, -5, -1, 0, 1, 5, 7, 42}) assert(std::hermite(n, x) == std::hermite(n, static_cast(x))); } }; From f01e17a8f3c164ecb7958edda54b4891f01e6a68 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:21 +0200 Subject: [PATCH 76/80] export functions for module usage --- libcxx/modules/std.compat/cmath.inc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libcxx/modules/std.compat/cmath.inc b/libcxx/modules/std.compat/cmath.inc index 6c86d0df57406..747bf851a257e 100644 --- a/libcxx/modules/std.compat/cmath.inc +++ b/libcxx/modules/std.compat/cmath.inc @@ -265,4 +265,7 @@ export { using ::signbit _LIBCPP_USING_IF_EXISTS; // [sf.cmath], mathematical special functions + using ::hermite; + using ::hermitef; + using ::hermitel; } // export From bb43f5a3db9904148a7002ee16c46941cd5920bb Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:21 +0200 Subject: [PATCH 77/80] Revert "export functions for module usage" This reverts commit 165fc118554d4be52898020fbe6edf108e41a217. --- libcxx/modules/std.compat/cmath.inc | 3 --- 1 file changed, 3 deletions(-) diff --git a/libcxx/modules/std.compat/cmath.inc b/libcxx/modules/std.compat/cmath.inc index 747bf851a257e..6c86d0df57406 100644 --- a/libcxx/modules/std.compat/cmath.inc +++ b/libcxx/modules/std.compat/cmath.inc @@ -265,7 +265,4 @@ export { using ::signbit _LIBCPP_USING_IF_EXISTS; // [sf.cmath], mathematical special functions - using ::hermite; - using ::hermitef; - using ::hermitel; } // export From bc27d9c54cfea3370c0601c9d510fedbe654e2f1 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:21 +0200 Subject: [PATCH 78/80] Adds a work-around to pass the module tests. --- libcxx/utils/libcxx/test/modules.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libcxx/utils/libcxx/test/modules.py b/libcxx/utils/libcxx/test/modules.py index aab7651c7bb03..b7758dc9a41ee 100644 --- a/libcxx/utils/libcxx/test/modules.py +++ b/libcxx/utils/libcxx/test/modules.py @@ -76,6 +76,13 @@ # This declaration is in the ostream header. ExtraDeclarations["system_error"] = ["std::operator<<"] +# TODO MODULES avoid this work-around +# This is a work-around for the special math functions. They are declared in +# __math/special_functions.h. Adding this as an ExtraHeader works for the std +# module. However these functions are special; they are not available in the +# global namespace. +ExtraDeclarations["cmath"] = ["std::hermite", "std::hermitef", "std::hermitel"] + ### ExtraHeader # Adds extra headers file to scan From 7cb43b00594add7d659fe0b62ab8aeeb6921de4a Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 7 Jul 2024 19:32:22 +0200 Subject: [PATCH 79/80] fix test: unsupported case must also return a value --- libcxx/test/std/numerics/c.math/hermite.pass.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp index 6d4aa697434c6..08fbd5c3283c1 100644 --- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp +++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp @@ -195,8 +195,9 @@ std::vector get_roots(unsigned n) { T(4.6036824495507), T(5.3874808900112)}; - default: + default: // polynom degree n>20 is unsupported assert(false); + return {T(-42)}; } } From 6a6fce8a1673355fc72f6ddfbbc1fa3d9d2d9d87 Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 17 Jul 2024 21:40:55 +0200 Subject: [PATCH 80/80] remove wrongly added code --- libcxx/include/cmath | 155 ------------------------------------------- 1 file changed, 155 deletions(-) diff --git a/libcxx/include/cmath b/libcxx/include/cmath index 70838f69bd8a1..3c22604a683c3 100644 --- a/libcxx/include/cmath +++ b/libcxx/include/cmath @@ -619,161 +619,6 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool __constexpr_isfinite(_A1 __lcpp_x) return __builtin_isfinite(__lcpp_x); } -_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI float __constexpr_copysign(float __x, float __y) _NOEXCEPT { - return __builtin_copysignf(__x, __y); -} - -_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI double __constexpr_copysign(double __x, double __y) _NOEXCEPT { - return __builtin_copysign(__x, __y); -} - -_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI long double -__constexpr_copysign(long double __x, long double __y) _NOEXCEPT { - return __builtin_copysignl(__x, __y); -} - -template ::value && std::is_arithmetic<_A2>::value, int> = 0> -_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI typename __promote<_A1, _A2>::type -__constexpr_copysign(_A1 __x, _A2 __y) _NOEXCEPT { - typedef typename std::__promote<_A1, _A2>::type __result_type; - static_assert((!(std::_IsSame<_A1, __result_type>::value && std::_IsSame<_A2, __result_type>::value)), ""); - return __builtin_copysign((__result_type)__x, (__result_type)__y); -} - -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR float __constexpr_fabs(float __x) _NOEXCEPT { - return __builtin_fabsf(__x); -} - -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR double __constexpr_fabs(double __x) _NOEXCEPT { - return __builtin_fabs(__x); -} - -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR long double __constexpr_fabs(long double __x) _NOEXCEPT { - return __builtin_fabsl(__x); -} - -template ::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR double __constexpr_fabs(_Tp __x) _NOEXCEPT { - return __builtin_fabs(static_cast(__x)); -} - -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 float __constexpr_fmax(float __x, float __y) _NOEXCEPT { -#if !__has_constexpr_builtin(__builtin_fmaxf) - if (__libcpp_is_constant_evaluated()) { - if (std::__constexpr_isnan(__x)) - return __y; - if (std::__constexpr_isnan(__y)) - return __x; - return __x < __y ? __y : __x; - } -#endif - return __builtin_fmaxf(__x, __y); -} - -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 double __constexpr_fmax(double __x, double __y) _NOEXCEPT { -#if !__has_constexpr_builtin(__builtin_fmax) - if (__libcpp_is_constant_evaluated()) { - if (std::__constexpr_isnan(__x)) - return __y; - if (std::__constexpr_isnan(__y)) - return __x; - return __x < __y ? __y : __x; - } -#endif - return __builtin_fmax(__x, __y); -} - -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 long double -__constexpr_fmax(long double __x, long double __y) _NOEXCEPT { -#if !__has_constexpr_builtin(__builtin_fmaxl) - if (__libcpp_is_constant_evaluated()) { - if (std::__constexpr_isnan(__x)) - return __y; - if (std::__constexpr_isnan(__y)) - return __x; - return __x < __y ? __y : __x; - } -#endif - return __builtin_fmaxl(__x, __y); -} - -template ::value && is_arithmetic<_Up>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename __promote<_Tp, _Up>::type -__constexpr_fmax(_Tp __x, _Up __y) _NOEXCEPT { - using __result_type = typename __promote<_Tp, _Up>::type; - return std::__constexpr_fmax(static_cast<__result_type>(__x), static_cast<__result_type>(__y)); -} - -template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __constexpr_logb(_Tp __x) { -#if !__has_constexpr_builtin(__builtin_logb) - if (__libcpp_is_constant_evaluated()) { - if (__x == _Tp(0)) { - // raise FE_DIVBYZERO - return -numeric_limits<_Tp>::infinity(); - } - - if (std::__constexpr_isinf(__x)) - return numeric_limits<_Tp>::infinity(); - - if (std::__constexpr_isnan(__x)) - return numeric_limits<_Tp>::quiet_NaN(); - - __x = std::__constexpr_fabs(__x); - unsigned long long __exp = 0; - while (__x >= numeric_limits<_Tp>::radix) { - __x /= numeric_limits<_Tp>::radix; - __exp += 1; - } - return _Tp(__exp); - } -#endif // !__has_constexpr_builtin(__builtin_logb) - return __builtin_logb(__x); -} - -template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp __constexpr_scalbn(_Tp __x, int __exp) { -#if !__has_constexpr_builtin(__builtin_scalbln) - if (__libcpp_is_constant_evaluated()) { - if (__x == _Tp(0)) - return __x; - - if (std::__constexpr_isinf(__x)) - return __x; - - if (__exp == _Tp(0)) - return __x; - - if (std::__constexpr_isnan(__x)) - return numeric_limits<_Tp>::quiet_NaN(); - - _Tp __mult(1); - if (__exp > 0) { - __mult = numeric_limits<_Tp>::radix; - --__exp; - } else { - ++__exp; - __exp = -__exp; - __mult /= numeric_limits<_Tp>::radix; - } - - while (__exp > 0) { - if (!(__exp & 1)) { - __mult *= __mult; - __exp >>= 1; - } else { - __x *= __mult; - --__exp; - } - } - return __x; - } -#endif // !__has_constexpr_builtin(__builtin_scalbln) - return __builtin_scalbn(__x, __exp); -} - #if _LIBCPP_STD_VER >= 20 template _LIBCPP_HIDE_FROM_ABI constexpr _Fp __lerp(_Fp __a, _Fp __b, _Fp __t) noexcept {