[libcxx-commits] [libcxx] [libc++][math] Mathematical Special Functions: Hermite Polynomial (PR #89982)

via libcxx-commits libcxx-commits at lists.llvm.org
Sat May 4 11:58:52 PDT 2024


https://github.com/PaulXiCao updated https://github.com/llvm/llvm-project/pull/89982

>From 0f3397f9ceca9f61b12368c06aceb029c8ffacfe Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sat, 20 Apr 2024 20:59:20 +0200
Subject: [PATCH 01/69] 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 00000000000000..daa89129fc8de3
--- /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 <experimental/__config>
+#include <cmath>
+#include <limits>
+
+/// \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 <class _Real>
+_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 <class _Real> _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 00000000000000..a7fc6cfbde20ec
--- /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 <experimental/__config>
+#include <cmath>
+#include <limits>
+#include <stdexcept>
+
+/// \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 <class _Real>
+_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 <class _Real>
+_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 <class _Real> _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 00000000000000..d2be9b48422260
--- /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 <experimental/__config>
+#include <cmath>
+#include <limits>
+#include <stdexcept>
+
+/// \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 <class _Real>
+_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 <class _Real> _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 <class _Real>
+_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 <class _Real>
+_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 00000000000000..9fd5d4fcbe190d
--- /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 <experimental/__config>
+#include <cmath>
+
+#if _LIBCPP_STD_VER > 14
+
+#include <experimental/__hermite>
+#include <experimental/__laguerre>
+#include <experimental/__legendre>
+
+_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL
+
+inline _LIBCPP_INLINE_VISIBILITY double assoc_laguerre(unsigned __lcpp_n, unsigned __lcpp_m, double __lcpp_x)
+{
+    return __libcpp_assoc_laguerre<double>(__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<float>(__libcpp_assoc_laguerre<double>(__lcpp_n , __lcpp_m, static_cast<double>(__lcpp_x)));
+}
+inline _LIBCPP_INLINE_VISIBILITY long double assoc_laguerrel(unsigned __lcpp_n, unsigned __lcpp_m, long double __lcpp_x)
+{
+    return __libcpp_assoc_laguerre<long double>(__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<double>(__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<float>(__libcpp_assoc_legendre<double>(__lcpp_n , __lcpp_m, static_cast<double>(__lcpp_x)));
+}
+inline _LIBCPP_INLINE_VISIBILITY long double assoc_legendrel(unsigned __lcpp_n, unsigned __lcpp_m, long double __lcpp_x)
+{
+    return __libcpp_assoc_legendre<long double>(__lcpp_n , __lcpp_m, __lcpp_x);
+}
+
+
+inline _LIBCPP_INLINE_VISIBILITY double laguerre(unsigned __lcpp_n, double __lcpp_x)
+{
+    return __libcpp_laguerre<double>(__lcpp_n ,__lcpp_x);
+}
+inline _LIBCPP_INLINE_VISIBILITY float laguerref(unsigned __lcpp_n, float __lcpp_x)
+{
+    return static_cast<float>(__libcpp_laguerre<double>(__lcpp_n, static_cast<double>(__lcpp_x)));
+}
+inline _LIBCPP_INLINE_VISIBILITY long double laguerrel(unsigned __lcpp_n, long double __lcpp_x)
+{
+    return __libcpp_laguerre<long double>(__lcpp_n ,__lcpp_x);
+}
+
+
+inline _LIBCPP_INLINE_VISIBILITY double legendre(unsigned __lcpp_n, double __lcpp_x)
+{
+    return __libcpp_legendre<double>(__lcpp_n ,__lcpp_x);
+}
+inline _LIBCPP_INLINE_VISIBILITY float legendref(unsigned __lcpp_n, float __lcpp_x)
+{
+    return static_cast<float>(__libcpp_legendre<double>(__lcpp_n, static_cast<double>(__lcpp_x)));
+}
+inline _LIBCPP_INLINE_VISIBILITY long double legendrel(unsigned __lcpp_n, long double __lcpp_x)
+{
+    return __libcpp_legendre<long double>(__lcpp_n ,__lcpp_x);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY double hermite(unsigned __lcpp_n, double __lcpp_x)
+{
+    return __libcpp_hermite<double>(__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<float>(__libcpp_hermite(__lcpp_n , static_cast<double>(__lcpp_x)));
+}
+inline _LIBCPP_INLINE_VISIBILITY long double hermitel(unsigned __lcpp_n, long double __lcpp_x)
+{
+    return __libcpp_hermite<long double>(__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 00000000000000..10261f017ad70e
--- /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
+//
+//===----------------------------------------------------------------------===//
+
+// <experimental/cmath>
+
+#include <cassert>
+#include <experimental/cmath>
+#include <limits>
+
+#if _LIBCPP_STD_VER > 14
+
+template <class T> void testAssocLaguerreNaNPropagation() {
+  const unsigned MaxN = 127;
+  const T x = std::numeric_limits<T>::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 <class T> 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 <class T> 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 <class T>
+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 <class T>
+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 <class T>
+void testAssocLaguerre(const T AbsTolerance, const T RelTolerance) {
+  testAssocLaguerreNaNPropagation<T>();
+  testAssocLaguerreThrows<T>(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<float>(1e-5f, 1e-5f);
+  testAssocLaguerre<double>(1e-9, 1e-9);
+  testAssocLaguerre<long double>(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 00000000000000..029f8cbf3d852d
--- /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
+//
+//===----------------------------------------------------------------------===//
+
+// <experimental/cmath>
+
+#include <cassert>
+#include <experimental/cmath>
+#include <limits>
+
+#if _LIBCPP_STD_VER > 14
+
+template <class T> void testAssocLegendreNaNPropagation() {
+  const unsigned MaxN = 127;
+  const T x = std::numeric_limits<T>::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 <class T> 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 <class T> 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 <class T>
+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 <class T>
+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 <class T>
+void testAssocLegendre(const T AbsTolerance, const T RelTolerance) {
+  testAssocLegendreNaNPropagation<T>();
+  testAssocLegendreThrows<T>(T(-5));
+  testAssocLegendreThrows<T>(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<float>(1e-6f, 1e-6f);
+  testAssocLegendre<double>(1e-9, 1e-9);
+  testAssocLegendre<long double>(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 00000000000000..38cddf6025f612
--- /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
+//
+//===----------------------------------------------------------------------===//
+
+// <experimental/cmath>
+
+#include <cassert>
+#include <experimental/cmath>
+#include <iostream>
+#include <limits>
+#include <vector>
+
+#if _LIBCPP_STD_VER > 14
+
+template <class T> void testHermiteNaNPropagation() {
+  const unsigned MaxN = 127;
+  const T x = std::numeric_limits<T>::quiet_NaN();
+  for (unsigned n = 0; n <= MaxN; ++n) {
+    assert(std::isnan(std::experimental::hermite(n, x)));
+  }
+}
+
+template <class T> 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 <class T>
+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 <class T>
+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 <class T> 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 <class T> std::vector<T> 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 <class T> void testHermiteRoots(T Tolerance) {
+  for (unsigned n = 0; n <= 20u; ++n) {
+    const auto Roots = getHermiteRoots<T>(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 <class T>
+void testHermite(const T AbsTolerance, const T RelTolerance) {
+  testHermiteNaNPropagation<T>();
+  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<float>(1e-6f, 1e-6f);
+  testHermite<double>(1e-9, 1e-9);
+  testHermite<long double>(1e-12l, 1e-12l);
+
+  testRecurrenceRelation<float>(1e-6f, 1e-6f);
+  testRecurrenceRelation<double>(1e-9, 1e-9);
+  testRecurrenceRelation<long double>(1e-12l, 1e-12l);
+
+  testHermiteRoots<float>(1e-6f);
+  testHermiteRoots<double>(1e-9);
+  testHermiteRoots<long double>(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 00000000000000..9856ca4838160a
--- /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
+//
+//===----------------------------------------------------------------------===//
+
+// <experimental/cmath>
+
+#include <cassert>
+#include <experimental/cmath>
+#include <limits>
+
+#if _LIBCPP_STD_VER > 14
+
+template <class T> void testLaguerreNaNPropagation() {
+  const unsigned MaxN = 127;
+  const T x = std::numeric_limits<T>::quiet_NaN();
+  for (unsigned n = 0; n <= MaxN; ++n) {
+    assert(std::isnan(std::experimental::laguerre(n, x)));
+  }
+}
+
+template <class T> 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 <class T> 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 <class T>
+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 <class T>
+void testLaguerre(const T AbsTolerance, const T RelTolerance) {
+  testLaguerreNaNPropagation<T>();
+  testLaguerreThrows<T>(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<float>(1e-6f, 1e-6f);
+  testLaguerre<double>(1e-9, 1e-9);
+  testLaguerre<long double>(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 00000000000000..79a555c5bb78e3
--- /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
+//
+//===----------------------------------------------------------------------===//
+
+// <experimental/cmath>
+
+#include <cassert>
+#include <experimental/cmath>
+#include <limits>
+
+#if _LIBCPP_STD_VER > 14
+
+template <class T> void testLegendreNaNPropagation() {
+  const unsigned MaxN = 127;
+  const T x = std::numeric_limits<T>::quiet_NaN();
+  for (unsigned n = 0; n <= MaxN; ++n) {
+    assert(std::isnan(std::experimental::legendre(n, x)));
+  }
+}
+
+template <class T> 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 <class T> 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 <class T>
+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 <class T>
+void testLegendre(const T AbsTolerance, const T RelTolerance) {
+  testLegendreNaNPropagation<T>();
+  testLegendreThrows<T>(T(-5));
+  testLegendreThrows<T>(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<float>(1e-6f, 1e-6f);
+  testLegendre<double>(1e-9, 1e-9);
+  testLegendre<long double>(1e-12, 1e-12);
+#endif
+  return 0;
+}

>From 8c40b62faabcdc9f5a0473f439d178d61a4d344c Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sat, 20 Apr 2024 23:08:49 +0200
Subject: [PATCH 02/69] 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 daa89129fc8de3..c93e05ae11303a 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 <experimental/__config>
 #include <cmath>
@@ -47,4 +48,4 @@ template <class _Real> _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 a7fc6cfbde20ec..bf1140eb75aa05 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 <experimental/__config>
 #include <cmath>
@@ -68,4 +69,4 @@ template <class _Real> _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 d2be9b48422260..aa4e1688531791 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 <experimental/__config>
 #include <cmath>
@@ -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 9fd5d4fcbe190d..18289a97ae5a32 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 <experimental/__hermite>
-#include <experimental/__laguerre>
-#include <experimental/__legendre>
+#include <experimental/__math/hermite.h>
+#include <experimental/__math/laguerre.h>
+#include <experimental/__math/legendre.h>
 
 _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 10261f017ad70e..945b4d531c9249 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 @@
 // <experimental/cmath>
 
 #include <cassert>
-#include <experimental/cmath>
+#include <experimental/math>
 #include <limits>
 
 #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 029f8cbf3d852d..3de555cac6f361 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 @@
 // <experimental/cmath>
 
 #include <cassert>
-#include <experimental/cmath>
+#include <experimental/math>
 #include <limits>
 
 #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 38cddf6025f612..e8b89b5e746e00 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 @@
 // <experimental/cmath>
 
 #include <cassert>
-#include <experimental/cmath>
+#include <experimental/math>
 #include <iostream>
 #include <limits>
 #include <vector>
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 9856ca4838160a..6c25cb83788fc6 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 @@
 // <experimental/cmath>
 
 #include <cassert>
-#include <experimental/cmath>
+#include <experimental/math>
 #include <limits>
 
 #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 79a555c5bb78e3..35cad4bff9561e 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 @@
 // <experimental/cmath>
 
 #include <cassert>
-#include <experimental/cmath>
+#include <experimental/math>
 #include <limits>
 
 #if _LIBCPP_STD_VER > 14

>From 34fb10a9951a64f3448831a9884b1c5f2a01205e Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sat, 20 Apr 2024 23:36:26 +0200
Subject: [PATCH 03/69] 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 4ecd834c5382ae..15e7e892f81a00 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -922,6 +922,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
@@ -932,6 +935,7 @@ set(files
   experimental/__simd/utility.h
   experimental/__simd/vec_ext.h
   experimental/iterator
+  experimental/math
   experimental/memory
   experimental/propagate_const
   experimental/simd

>From 4572f3ab675aff7a0d8abc2fcf1dc2ebdbd36c2e Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sun, 21 Apr 2024 14:53:49 +0200
Subject: [PATCH 04/69] 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 9debdf0a97db69e3e93cd07b51630310bca5c6de Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sun, 21 Apr 2024 21:54:11 +0200
Subject: [PATCH 05/69] 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 bf1140eb75aa05..58b92345beb812 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 <class _Real> _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 aa4e1688531791..ae98e6153278bf 100644
--- a/libcxx/include/experimental/__math/legendre.h
+++ b/libcxx/include/experimental/__math/legendre.h
@@ -51,7 +51,7 @@ template <class _Real> _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 3d0bc681bc27fb54e1e47a1a2d161a8b603f8d6d Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sun, 21 Apr 2024 22:04:17 +0200
Subject: [PATCH 06/69] 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 18289a97ae5a32..b2b76e913c0496 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<double>(__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<float>(__libcpp_assoc_laguerre<double>(__lcpp_n , __lcpp_m, static_cast<double>(__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<long double>(__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<double>(__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<float>(__libcpp_assoc_legendre<double>(__lcpp_n , __lcpp_m, static_cast<double>(__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<long double>(__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<double>(__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<float>(__libcpp_laguerre<double>(__lcpp_n, static_cast<double>(__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<long double>(__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<double>(__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<float>(__libcpp_legendre<double>(__lcpp_n, static_cast<double>(__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<long double>(__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<double>(__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<float>(__libcpp_hermite(__lcpp_n , static_cast<double>(__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<long double>(__lcpp_n ,__lcpp_x);
 }

>From d5f0e4659c795d488d5664fb0c31e4a762f451ea Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sun, 21 Apr 2024 22:09:42 +0200
Subject: [PATCH 07/69] 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 e8b89b5e746e00..06522cdcb5d32d 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 1da97b4d62f53ec7674181d62a41c6d3689042b6 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sun, 21 Apr 2024 22:11:54 +0200
Subject: [PATCH 08/69] 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 6c25cb83788fc6..f6a11221e25009 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 3721e893c074c0fe22521311ba0b55207d3d0cf1 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sun, 21 Apr 2024 22:13:24 +0200
Subject: [PATCH 09/69] 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 35cad4bff9561e..493b1c10f345f8 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 c5cda4e5fa9f6a0bb6e491af7ae1a4cb52813bf5 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sun, 21 Apr 2024 22:14:26 +0200
Subject: [PATCH 10/69] 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 945b4d531c9249..793a723116d48d 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 e8443b1e4f4929403b1e4e72d20b34afcb6bc6ed Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sun, 21 Apr 2024 22:15:12 +0200
Subject: [PATCH 11/69] 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 3de555cac6f361..ed9b1e1f9178d8 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 52de5c97fb9206fc623db556e1c174b5d75adb1e Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sun, 21 Apr 2024 23:10:05 +0200
Subject: [PATCH 12/69] 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 c93e05ae11303a..ebd4555b4a49e1 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 <class _Real>
 _Real __libcpp_hermite_recurrence(unsigned __n, _Real __x) {
   if (__n == 0u)

>From b500da25c7e14a0bf54e1678180a7f1c1a2d142d Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sun, 21 Apr 2024 23:39:03 +0200
Subject: [PATCH 13/69] 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 ebd4555b4a49e1..b89cb0b27b6d98 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 <class _Real>
 _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 <class _Real> _Real __libcpp_hermite(unsigned __n, _Real __x) {

>From 6d5ef58aa041836b0352f26e2847ea9ab1f51f43 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sun, 21 Apr 2024 23:57:13 +0200
Subject: [PATCH 14/69] 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 64652c8307c9e6..eb0e4de920ab9c 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 6feadb53ab55e131d6ea47e81c5ac2bb8e6de856 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sun, 21 Apr 2024 23:58:10 +0200
Subject: [PATCH 15/69] 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 bccae353b0c6bd..690458887460a4 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 d711e58716d8a662780ba10192924e501fd3f5a9 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Mon, 22 Apr 2024 12:42:17 +0200
Subject: [PATCH 16/69] 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 15e7e892f81a00..30c00e033fe1b0 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -923,8 +923,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 58b92345beb812..00000000000000
--- 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 <experimental/__config>
-#include <cmath>
-#include <limits>
-#include <stdexcept>
-
-/// \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 <class _Real>
-_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 <class _Real>
-_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 <class _Real> _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 ae98e6153278bf..00000000000000
--- 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 <experimental/__config>
-#include <cmath>
-#include <limits>
-#include <stdexcept>
-
-/// \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 <class _Real>
-_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 <class _Real> _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 <class _Real>
-_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 <class _Real>
-_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 b2b76e913c0496..a0a4f70ad42378 100644
--- a/libcxx/include/experimental/math
+++ b/libcxx/include/experimental/math
@@ -20,66 +20,9 @@
 #if _LIBCPP_STD_VER > 14
 
 #include <experimental/__math/hermite.h>
-#include <experimental/__math/laguerre.h>
-#include <experimental/__math/legendre.h>
 
 _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<double>(__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<float>(__libcpp_assoc_laguerre<double>(__lcpp_n , __lcpp_m, static_cast<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<long double>(__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<double>(__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<float>(__libcpp_assoc_legendre<double>(__lcpp_n , __lcpp_m, static_cast<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<long double>(__lcpp_n , __lcpp_m, __lcpp_x);
-}
-
-
-inline _LIBCPP_HIDE_FROM_ABI double laguerre(unsigned __lcpp_n, double __lcpp_x)
-{
-    return __libcpp_laguerre<double>(__lcpp_n ,__lcpp_x);
-}
-inline _LIBCPP_HIDE_FROM_ABI float laguerref(unsigned __lcpp_n, float __lcpp_x)
-{
-    return static_cast<float>(__libcpp_laguerre<double>(__lcpp_n, static_cast<double>(__lcpp_x)));
-}
-inline _LIBCPP_HIDE_FROM_ABI long double laguerrel(unsigned __lcpp_n, long double __lcpp_x)
-{
-    return __libcpp_laguerre<long double>(__lcpp_n ,__lcpp_x);
-}
-
-
-inline _LIBCPP_HIDE_FROM_ABI double legendre(unsigned __lcpp_n, double __lcpp_x)
-{
-    return __libcpp_legendre<double>(__lcpp_n ,__lcpp_x);
-}
-inline _LIBCPP_HIDE_FROM_ABI float legendref(unsigned __lcpp_n, float __lcpp_x)
-{
-    return static_cast<float>(__libcpp_legendre<double>(__lcpp_n, static_cast<double>(__lcpp_x)));
-}
-inline _LIBCPP_HIDE_FROM_ABI long double legendrel(unsigned __lcpp_n, long double __lcpp_x)
-{
-    return __libcpp_legendre<long double>(__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 793a723116d48d..00000000000000
--- 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
-//
-//===----------------------------------------------------------------------===//
-
-// <experimental/cmath>
-
-#include <cassert>
-#include <experimental/math>
-#include <limits>
-
-#if _LIBCPP_STD_VER > 14
-
-template <class T> void testAssocLaguerreNaNPropagation() {
-  const unsigned MaxN = 127;
-  const T x = std::numeric_limits<T>::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 <class T> 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 <class T> 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 <class T>
-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 <class T>
-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 <class T>
-void testAssocLaguerre(const T AbsTolerance, const T RelTolerance) {
-  testAssocLaguerreNaNPropagation<T>();
-  testAssocLaguerreThrows<T>(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<float>(1e-5f, 1e-5f);
-  testAssocLaguerre<double>(1e-9, 1e-9);
-  testAssocLaguerre<long double>(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 ed9b1e1f9178d8..00000000000000
--- 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
-//
-//===----------------------------------------------------------------------===//
-
-// <experimental/cmath>
-
-#include <cassert>
-#include <experimental/math>
-#include <limits>
-
-#if _LIBCPP_STD_VER > 14
-
-template <class T> void testAssocLegendreNaNPropagation() {
-  const unsigned MaxN = 127;
-  const T x = std::numeric_limits<T>::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 <class T> 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 <class T> 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 <class T>
-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 <class T>
-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 <class T>
-void testAssocLegendre(const T AbsTolerance, const T RelTolerance) {
-  testAssocLegendreNaNPropagation<T>();
-  testAssocLegendreThrows<T>(T(-5));
-  testAssocLegendreThrows<T>(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<float>(1e-6f, 1e-6f);
-  testAssocLegendre<double>(1e-9, 1e-9);
-  testAssocLegendre<long double>(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 f6a11221e25009..00000000000000
--- 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
-//
-//===----------------------------------------------------------------------===//
-
-// <experimental/cmath>
-
-#include <cassert>
-#include <experimental/math>
-#include <limits>
-
-#if _LIBCPP_STD_VER > 14
-
-template <class T> void testLaguerreNaNPropagation() {
-  const unsigned MaxN = 127;
-  const T x = std::numeric_limits<T>::quiet_NaN();
-  for (unsigned n = 0; n <= MaxN; ++n) {
-    assert(std::isnan(std::experimental::laguerre(n, x)));
-  }
-}
-
-template <class T> 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 <class T> 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 <class T>
-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 <class T>
-void testLaguerre(const T AbsTolerance, const T RelTolerance) {
-  testLaguerreNaNPropagation<T>();
-  testLaguerreThrows<T>(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<float>(1e-6f, 1e-6f);
-  testLaguerre<double>(1e-9, 1e-9);
-  testLaguerre<long double>(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 493b1c10f345f8..00000000000000
--- 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
-//
-//===----------------------------------------------------------------------===//
-
-// <experimental/cmath>
-
-#include <cassert>
-#include <experimental/math>
-#include <limits>
-
-#if _LIBCPP_STD_VER > 14
-
-template <class T> void testLegendreNaNPropagation() {
-  const unsigned MaxN = 127;
-  const T x = std::numeric_limits<T>::quiet_NaN();
-  for (unsigned n = 0; n <= MaxN; ++n) {
-    assert(std::isnan(std::experimental::legendre(n, x)));
-  }
-}
-
-template <class T> 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 <class T> 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 <class T>
-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 <class T>
-void testLegendre(const T AbsTolerance, const T RelTolerance) {
-  testLegendreNaNPropagation<T>();
-  testLegendreThrows<T>(T(-5));
-  testLegendreThrows<T>(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<float>(1e-6f, 1e-6f);
-  testLegendre<double>(1e-9, 1e-9);
-  testLegendre<long double>(1e-12, 1e-12);
-#endif
-  return 0;
-}

>From 8c284b98de68c680bee5f3d7bb17ecb1b9d9a91c Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Mon, 22 Apr 2024 12:47:07 +0200
Subject: [PATCH 17/69] 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 b89cb0b27b6d98..11eac3cfc691cc 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 <class _Real>
 _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 a63f7664906b92f3940771e7db0c4fab1eacf6ee Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Mon, 22 Apr 2024 13:07:25 +0200
Subject: [PATCH 18/69] 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 a0a4f70ad42378..c9e39cb961c656 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<double>(__lcpp_n ,__lcpp_x);
+    return __libcpp_hermite<double>(__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<float>(__libcpp_hermite(__lcpp_n , static_cast<double>(__lcpp_x)));
+    return static_cast<float>(__libcpp_hermite(__n, static_cast<double>(__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<long double>(__lcpp_n ,__lcpp_x);
+    return __libcpp_hermite<long double>(__n, __x);
 }
 
 

>From 2c17683ec28e289cb28558ec2e63f16293cbd68c Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Mon, 22 Apr 2024 13:13:22 +0200
Subject: [PATCH 19/69] 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 c9e39cb961c656..3039a90815919d 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<double>(__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<long double>(__n, __x);
+    return __libcpp_hermite(__n, __x);
 }
 
 

>From 3105f4ec15046fc8c88df5083042043d2ae62310 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Mon, 22 Apr 2024 13:14:42 +0200
Subject: [PATCH 20/69] 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 11eac3cfc691cc..09d12e4e17c29a 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 <class _Real>
-_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 <class _Real> _Real __libcpp_hermite(unsigned __n, _Real __x) {
+template <class _Real> _Real __libcpp_hermite(const unsigned __n, const _Real __x) {
   if (std::isnan(__x))
     return std::numeric_limits<_Real>::quiet_NaN();
 

>From 38b3db96156b80cc05c71a5e697f494e81343fce Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Mon, 22 Apr 2024 13:17:24 +0200
Subject: [PATCH 21/69] 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 09d12e4e17c29a..a1ad77c32a4ec5 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 <class _Real> _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 5dd9791414ad87e781bd29b7f926c090f88d97f5 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Mon, 22 Apr 2024 13:24:20 +0200
Subject: [PATCH 22/69] 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 a1ad77c32a4ec5..b95e7a084ff877 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 <experimental/__config>
 #include <cmath>
+#include <experimental/__config>
 #include <limits>
 
 /// \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 <class _Real> _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 <class _Real>
+_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 3039a90815919d..604a5732816660 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 <experimental/__config>
 #include <cmath>
+#include <experimental/__config>
 
 #if _LIBCPP_STD_VER > 14
 
-#include <experimental/__math/hermite.h>
+#  include <experimental/__math/hermite.h>
 
 _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<float>(__libcpp_hermite(__n, static_cast<double>(__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<float>(__libcpp_hermite(__n, static_cast<double>(__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 06522cdcb5d32d..6347da68fe22d4 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 <class T> void testHermiteNaNPropagation() {
+template <class T>
+void testHermiteNaNPropagation() {
   const unsigned MaxN = 127;
-  const T x = std::numeric_limits<T>::quiet_NaN();
+  const T x           = std::numeric_limits<T>::quiet_NaN();
   for (unsigned n = 0; n <= MaxN; ++n) {
     assert(std::isnan(std::experimental::hermite(n, x)));
   }
 }
 
-template <class T> void testHermiteNotNaN(const T x) {
+template <class T>
+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 <class T> void testHermiteNotNaN(const T x) {
 }
 
 template <class T>
-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 <class T> 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 <class T>
+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 <class T> 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 <class T> std::vector<T> getHermiteRoots(unsigned n) {
+template <class T>
+std::vector<T> getHermiteRoots(unsigned n) {
   if (n == 0u)
     return {};
   if (n == 1u)
@@ -107,40 +103,22 @@ template <class T> std::vector<T> 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 <class T> std::vector<T> 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 <class T> void testHermiteRoots(T Tolerance) {
+template <class T>
+void testHermiteRoots(T Tolerance) {
   for (unsigned n = 0; n <= 20u; ++n) {
     const auto Roots = getHermiteRoots<T>(n);
     for (T x : Roots) {
@@ -261,8 +240,7 @@ template <class T> void testHermiteRoots(T Tolerance) {
 template <class T>
 void testHermite(const T AbsTolerance, const T RelTolerance) {
   testHermiteNaNPropagation<T>();
-  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<float>(1e-6f, 1e-6f);
   testHermite<double>(1e-9, 1e-9);

>From 98a943867a653f284c5c1b1a71cdef9c0bf12d8b Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Mon, 22 Apr 2024 13:31:39 +0200
Subject: [PATCH 23/69] 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 b95e7a084ff877..23bc7b452cdfe8 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 <cmath>
+#include <cmath> // std::isnan
 #include <experimental/__config>
-#include <limits>
+#include <limits> // 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 604a5732816660..3b0703fb4bca57 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 <cmath>
 #include <experimental/__config>
 
-#if _LIBCPP_STD_VER > 14
+#if _LIBCPP_STD_VER >= 17
 
 #  include <experimental/__math/hermite.h>
 
@@ -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 5ec76d7dcc7142c7cd87e31d7dbe3ea3c306dd05 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Tue, 23 Apr 2024 23:11:33 +0200
Subject: [PATCH 24/69] 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 3b0703fb4bca57..5161381be0b613 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<float>(__libcpp_hermite(__n, static_cast<double>(__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 2e9052979cb876adaf4486e01bcc5d78e22a5022 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Wed, 24 Apr 2024 15:13:21 +0200
Subject: [PATCH 25/69] 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 5161381be0b613..2c633ff32df6da 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<float>(__libcpp_hermite(__n, static_cast<double>(__x)));
+  return static_cast<float>(hermite(__n, static_cast<double>(__x)));
 }
 
 inline _LIBCPP_HIDE_FROM_ABI long double hermite(unsigned __n, long double __x) { return __libcpp_hermite(__n, __x); }

>From 349e5a69bd439970574e1b997fd3fa90d9509ea4 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Wed, 24 Apr 2024 15:14:04 +0200
Subject: [PATCH 26/69] implement: template<class Integer> 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 2c633ff32df6da..21cf2a00d92feb 100644
--- a/libcxx/include/experimental/math
+++ b/libcxx/include/experimental/math
@@ -19,6 +19,7 @@
 #if _LIBCPP_STD_VER >= 17
 
 #  include <experimental/__math/hermite.h>
+#  include <type_traits> // 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<std::is_integral_v<_Integer>, double> hermite(unsigned int __n, _Integer __x) {
+  // use double internally -- see C++17 standard - 29.9.1.2.2
+  return hermite(__n, static_cast<double>(__x));
+}
+
 _LIBCPP_END_NAMESPACE_EXPERIMENTAL
 
 #endif // _LIBCPP_STD_VER >= 17

>From b3a6ff535aecfa9e0250545695e2bd5374c3d5fe Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Wed, 24 Apr 2024 15:21:01 +0200
Subject: [PATCH 27/69] 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 21cf2a00d92feb..b7847d5037bb6d 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 <experimental/__config>
 
 #if _LIBCPP_STD_VER >= 17

>From e5214cb398e1effb12b3b797768ceb02fd2ad795 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Wed, 24 Apr 2024 15:26:58 +0200
Subject: [PATCH 28/69] 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 6347da68fe22d4..27c25ffb737c7b 100644
--- a/libcxx/test/std/experimental/math/hermite.pass.cpp
+++ b/libcxx/test/std/experimental/math/hermite.pass.cpp
@@ -14,7 +14,7 @@
 #include <limits>
 #include <vector>
 
-#if _LIBCPP_STD_VER > 14
+// UNSUPPORTED: c++03, c++11, c++14
 
 template <class T>
 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<float>(1e-6f, 1e-6f);
   testHermite<double>(1e-9, 1e-9);
   testHermite<long double>(1e-12l, 1e-12l);
@@ -263,6 +260,6 @@ int main(int, char**) {
   testHermiteRoots<float>(1e-6f);
   testHermiteRoots<double>(1e-9);
   testHermiteRoots<long double>(1e-10l);
-#endif
+
   return 0;
 }

>From 1854b838a57902d2cab29376667bd4065d24216c Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Wed, 24 Apr 2024 22:00:29 +0200
Subject: [PATCH 29/69] 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 27c25ffb737c7b..dc4f7163808eb8 100644
--- a/libcxx/test/std/experimental/math/hermite.pass.cpp
+++ b/libcxx/test/std/experimental/math/hermite.pass.cpp
@@ -13,15 +13,21 @@
 #include <iostream>
 #include <limits>
 #include <vector>
+#include <array>
+
+#include <assert_macros.h>
 
 // UNSUPPORTED: c++03, c++11, c++14
 
+namespace {
+namespace ex = std::experimental;
+
 template <class T>
 void testHermiteNaNPropagation() {
   const unsigned MaxN = 127;
   const T x           = std::numeric_limits<T>::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 <class T>
-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 <class T>
-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 <class Integer>
+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<double>(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<float>(1e-6f, 1e-6f);
-  testHermite<double>(1e-9, 1e-9);
+  testHermite<float>(1e-5f, 1e-5f);
+  testHermite<double>(1e-11, 1e-11);
   testHermite<long double>(1e-12l, 1e-12l);
 
-  testRecurrenceRelation<float>(1e-6f, 1e-6f);
-  testRecurrenceRelation<double>(1e-9, 1e-9);
+  testHermiteF();
+  testHermiteL();
+
+  testRecurrenceRelation<float>(1e-5f, 1e-5f);
+  testRecurrenceRelation<double>(1e-11, 1e-11);
   testRecurrenceRelation<long double>(1e-12l, 1e-12l);
 
-  testHermiteRoots<float>(1e-6f);
+  testHermiteRoots<float>(1e-5f);
   testHermiteRoots<double>(1e-9);
   testHermiteRoots<long double>(1e-10l);
 
+  testHermiteByInteger<short>();
+  testHermiteByInteger<int>();
+  testHermiteByInteger<long>();
+  testHermiteByInteger<long long>();
+
   return 0;
 }

>From 2c72621167ff4ac8c1e9e9f74193dfd40782a48b Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Wed, 24 Apr 2024 22:05:25 +0200
Subject: [PATCH 30/69] 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 8952391afc83b6..ea01c9eec14790 100644
--- a/libcxx/docs/Status/Cxx17Papers.csv
+++ b/libcxx/docs/Status/Cxx17Papers.csv
@@ -26,7 +26,7 @@
 "`P0013R1 <https://wg21.link/p0013r1>`__","LWG","Logical type traits rev 2","Kona","|Complete|","3.8"
 "","","","","",""
 "`P0024R2 <https://wg21.link/P0024R2>`__","LWG","The Parallelism TS Should be Standardized","Jacksonville","|Partial|",""
-"`P0226R1 <https://wg21.link/P0226R1>`__","LWG","Mathematical Special Functions for C++17","Jacksonville","",""
+"`P0226R1 <https://wg21.link/P0226R1>`__","LWG","Mathematical Special Functions for C++17","Jacksonville","|In Progress|",""
 "`P0220R1 <https://wg21.link/P0220R1>`__","LWG","Adopt Library Fundamentals V1 TS Components for C++17","Jacksonville","|Complete|","16.0"
 "`P0218R1 <https://wg21.link/P0218R1>`__","LWG","Adopt the File System TS for C++17","Jacksonville","|Complete|","7.0"
 "`P0033R1 <https://wg21.link/P0033R1>`__","LWG","Re-enabling shared_from_this","Jacksonville","|Complete|","3.9"

>From 20def2e3c3a5c7af41f9180e249a8df21ba72298 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Thu, 25 Apr 2024 15:05:21 +0200
Subject: [PATCH 31/69] 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 eb0e4de920ab9c..9beb9c823a850b 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 a85b2bc71c075137926978ad5ab464dcd77f9171 Mon Sep 17 00:00:00 2001
From: Paul <>
Date: Fri, 26 Apr 2024 14:32:31 +0200
Subject: [PATCH 32/69] 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 23bc7b452cdfe8..7fecfae5141310 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 94435bec53e4b1e54d948869cb6ba15012e4570f Mon Sep 17 00:00:00 2001
From: Paul <>
Date: Fri, 26 Apr 2024 22:33:58 +0200
Subject: [PATCH 33/69] move out of experimental/

---
 libcxx/include/CMakeLists.txt                 |  2 -
 libcxx/include/cmath                          | 47 +++++++++++++++++++
 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, 63 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 30c00e033fe1b0..4ecd834c5382ae 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -922,7 +922,6 @@ set(files
   execution
   expected
   experimental/__config
-  experimental/__math/hermite.h
   experimental/__simd/aligned_tag.h
   experimental/__simd/declaration.h
   experimental/__simd/reference.h
@@ -933,7 +932,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 dd194bbb558969..bf2009d1b453d4 100644
--- a/libcxx/include/cmath
+++ b/libcxx/include/cmath
@@ -765,6 +765,53 @@ _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 <class _Real>
+_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<float>(hermite(__n, static_cast<double>(__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<std::is_integral_v<_Integer>, double> hermite(unsigned int __n, _Integer __x) {
+  // use double internally -- see C++17 standard - 29.9.1.2.2
+  return hermite(__n, static_cast<double>(__x));
+}
+#endif // _LIBCPP_STD_VER >= 17
+
 #if _LIBCPP_STD_VER >= 20
 template <typename _Fp>
 _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 7fecfae5141310..00000000000000
--- 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 <cmath> // std::isnan
-#include <experimental/__config>
-#include <limits> // 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 <class _Real>
-_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 <class _Real>
-_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 b7847d5037bb6d..00000000000000
--- 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 <experimental/__config>
-
-#if _LIBCPP_STD_VER >= 17
-
-#  include <experimental/__math/hermite.h>
-#  include <type_traits> // 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<float>(hermite(__n, static_cast<double>(__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<std::is_integral_v<_Integer>, double> hermite(unsigned int __n, _Integer __x) {
-  // use double internally -- see C++17 standard - 29.9.1.2.2
-  return hermite(__n, static_cast<double>(__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 9beb9c823a850b..64652c8307c9e6 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 dc4f7163808eb8..1067f431dbff76 100644
--- a/libcxx/test/std/experimental/math/hermite.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp
@@ -9,7 +9,7 @@
 // <experimental/cmath>
 
 #include <cassert>
-#include <experimental/math>
+#include <cmath>
 #include <iostream>
 #include <limits>
 #include <vector>
@@ -20,14 +20,12 @@
 // UNSUPPORTED: c++03, c++11, c++14
 
 namespace {
-namespace ex = std::experimental;
-
 template <class T>
 void testHermiteNaNPropagation() {
   const unsigned MaxN = 127;
   const T x           = std::numeric_limits<T>::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 <class T>
 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<double>(x)));
+      assert(std::hermite(n, x) == std::hermite(n, static_cast<double>(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 be6b88c7f3d70ab5922e0f49477ac9e4ae380e6f Mon Sep 17 00:00:00 2001
From: Paul <>
Date: Fri, 26 Apr 2024 22:36:08 +0200
Subject: [PATCH 34/69] 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 bf2009d1b453d4..a4bc4c6f16fa54 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 <class _Real>
-_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 33f4108d0468b70bdbf6ded73ee83e24a59bede3 Mon Sep 17 00:00:00 2001
From: Paul <>
Date: Fri, 26 Apr 2024 22:40:19 +0200
Subject: [PATCH 35/69] 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 a4bc4c6f16fa54..0e35229ab0143f 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 <class _Real>
 _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<std::is_integral_v<_Integer>, double> hermite(unsigned int __n, _Integer __x) {
+_LIBCPP_HIDE_FROM_ABI enable_if_t<is_integral_v<_Integer>, double> hermite(unsigned int __n, _Integer __x) {
   // use double internally -- see C++17 standard - 29.9.1.2.2
   return hermite(__n, static_cast<double>(__x));
 }

>From d1226cdd95646e1fd7cb2435c3ca0e004a6ad14c Mon Sep 17 00:00:00 2001
From: Paul <>
Date: Fri, 26 Apr 2024 22:42:32 +0200
Subject: [PATCH 36/69] 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 0e35229ab0143f..4172e7640caaa6 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 e2e2da87bf5b5ade98eba92946eb23804fc7fa5a Mon Sep 17 00:00:00 2001
From: Paul <>
Date: Fri, 26 Apr 2024 22:48:20 +0200
Subject: [PATCH 37/69] 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 1067f431dbff76..e26a4d9542da89 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 @@
 //
 //===----------------------------------------------------------------------===//
 
-// <experimental/cmath>
+// UNSUPPORTED: c++03, c++11, c++14
 
 #include <cassert>
 #include <cmath>
@@ -17,7 +17,6 @@
 
 #include <assert_macros.h>
 
-// UNSUPPORTED: c++03, c++11, c++14
 
 namespace {
 template <class T>

>From c9fa9b4fdd63d1feb94e1d5fc29145649df01107 Mon Sep 17 00:00:00 2001
From: Paul <>
Date: Fri, 26 Apr 2024 22:49:44 +0200
Subject: [PATCH 38/69] 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 4172e7640caaa6..d21e3d56135a6e 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 947071a5777e6114c2b852f619b6e05e664e7071 Mon Sep 17 00:00:00 2001
From: Paul <>
Date: Fri, 26 Apr 2024 23:09:36 +0200
Subject: [PATCH 39/69] 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 d21e3d56135a6e..2e2745388e24e9 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 40404493dc222d161dd46853a295d2117b1d137b Mon Sep 17 00:00:00 2001
From: Paul <>
Date: Fri, 26 Apr 2024 23:13:19 +0200
Subject: [PATCH 40/69] 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 2e2745388e24e9..072c4dc45eea9d 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 <class _Real>
-_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<float>(hermite(__n, static_cast<double>(__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 d4debd5f7751154cca1271c7f6a0c0979ed0c52b Mon Sep 17 00:00:00 2001
From: Paul <>
Date: Fri, 26 Apr 2024 23:16:25 +0200
Subject: [PATCH 41/69] 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 072c4dc45eea9d..c2c58296529872 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 <class _Integer>
 _LIBCPP_HIDE_FROM_ABI enable_if_t<is_integral_v<_Integer>, double> hermite(unsigned int __n, _Integer __x) {
   // use double internally -- see C++17 standard - 29.9.1.2.2
   return hermite(__n, static_cast<double>(__x));

>From 925349eced1575b1d3fbe1442b68ffc79d4f9f9b Mon Sep 17 00:00:00 2001
From: Paul <>
Date: Sat, 27 Apr 2024 12:45:41 +0200
Subject: [PATCH 42/69] 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 c2c58296529872..f54ffa903f2b97 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 <class _Real>
 _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<float>(hermite(__n, static_cast<double>(__x)));
+  return static_cast<float>(std::hermite(__n, static_cast<double>(__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 <class _Integer>
-_LIBCPP_HIDE_FROM_ABI enable_if_t<is_integral_v<_Integer>, double> hermite(unsigned int __n, _Integer __x) {
+_LIBCPP_HIDE_FROM_ABI std::enable_if_t<std::is_integral_v<_Integer>, double> hermite(unsigned int __n, _Integer __x) {
   // use double internally -- see C++17 standard - 29.9.1.2.2
-  return hermite(__n, static_cast<double>(__x));
+  return std::hermite(__n, static_cast<double>(__x));
 }
 #endif // _LIBCPP_STD_VER >= 17
 

>From be9c82e4313161d850a066817ea85f2f23e20725 Mon Sep 17 00:00:00 2001
From: Paul <>
Date: Sat, 27 Apr 2024 22:32:02 +0200
Subject: [PATCH 43/69] 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 e26a4d9542da89..397046219bb1fb 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 <cassert>
 #include <cmath>
-#include <iostream>
 #include <limits>
 #include <vector>
 #include <array>
 
 #include <assert_macros.h>
 
-
 namespace {
+
+inline constexpr unsigned MAX_N = 128;
+
 template <class T>
-void testHermiteNaNPropagation() {
-  const unsigned MaxN = 127;
-  const T x           = std::numeric_limits<T>::quiet_NaN();
-  for (unsigned n = 0; n <= MaxN; ++n) {
-    assert(std::isnan(std::hermite(n, x)));
-  }
+std::array<T, 7> sample_points() {
+  return {-1.0, -0.5, -0.1, 0.0, 0.1, 0.5, 1.0};
+}
+
+template <class T>
+void test_NaN_propagation() {
+  T NaN = std::numeric_limits<T>::quiet_NaN();
+  for (unsigned n = 0; n < MAX_N; ++n)
+    assert(std::isnan(std::hermite(n, NaN)));
 }
 
 template <class T>
-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 <class T>
-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 <class T>
+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<T> 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 <class T>
-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<T> 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 <class T>
-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<T>())
+    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 <class T>
-std::vector<T> getHermiteRoots(unsigned n) {
-  if (n == 0u)
+std::vector<T> 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<T> 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<T> 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<T> 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<T> 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<T> 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<T> 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<T> 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<T> 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<T> 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<T> 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 <class T>
-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<T>(n);
-    for (T x : Roots) {
+    for (T x : get_roots<T>(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 <class T>
-void testHermite(const T AbsTolerance, const T RelTolerance) {
-  testHermiteNaNPropagation<T>();
-  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<T>();
 
-  for (T x : Samples) {
-    testHermiteNotNaN(x);
-    testHermiteAnalytic(x, AbsTolerance, RelTolerance);
+  for (T x : sample_points<T>()) {
+    test_not_NaN(x);
+    test_analytic_solution(x, abs_tol, rel_tol);
   }
 }
 
 template <class Integer>
-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<double>(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<float>())
       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<long double>())
       assert(std::hermite(n, x) == std::hermitel(n, x));
 }
 } // namespace
 
 int main(int, char**) {
-  testHermite<float>(1e-5f, 1e-5f);
-  testHermite<double>(1e-11, 1e-11);
-  testHermite<long double>(1e-12l, 1e-12l);
+  test_hermite<float>(1e-5f, 1e-5f);
+  test_hermite<double>(1e-11, 1e-11);
+  test_hermite<long double>(1e-12l, 1e-12l);
 
-  testHermiteF();
-  testHermiteL();
+  test_hermitef();
+  test_hermitel();
 
-  testRecurrenceRelation<float>(1e-5f, 1e-5f);
-  testRecurrenceRelation<double>(1e-11, 1e-11);
-  testRecurrenceRelation<long double>(1e-12l, 1e-12l);
+  test_recurrence_relation<float>(1e-5f, 1e-5f);
+  test_recurrence_relation<double>(1e-11, 1e-11);
+  test_recurrence_relation<long double>(1e-12l, 1e-12l);
 
-  testHermiteRoots<float>(1e-5f);
-  testHermiteRoots<double>(1e-9);
-  testHermiteRoots<long double>(1e-10l);
+  test_roots<float>(1e-5f);
+  test_roots<double>(1e-9);
+  test_roots<long double>(1e-10l);
 
-  testHermiteByInteger<short>();
-  testHermiteByInteger<int>();
-  testHermiteByInteger<long>();
-  testHermiteByInteger<long long>();
+  test_integers<short>();
+  test_integers<int>();
+  test_integers<long>();
+  test_integers<long long>();
 
   return 0;
 }

>From 18a320a0f523d1939262d1cfc633da6e5fae4870 Mon Sep 17 00:00:00 2001
From: Paul <>
Date: Sun, 28 Apr 2024 15:18:05 +0200
Subject: [PATCH 44/69] 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 00000000000000..28045f3290fdd2
--- /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 00000000000000..be00c63e6fe3f7
--- /dev/null
+++ b/libcxx/docs/Status/SpecialMathPapers.csv
@@ -0,0 +1,2 @@
+Number,Name,Standard,Assignee,Status,First released version
+`P0226 <https://wg21.link/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 00000000000000..57be6c746c5906
--- /dev/null
+++ b/libcxx/docs/Status/SpecialMathProjects.csv
@@ -0,0 +1,22 @@
+Section,Description,Assignee,Complete
+| `[sf.cmath.assoc.laguerre] <https://wg21.link/sf.cmath.assoc.laguerre>`_, std::assoc_laguerre, None, |Not Started|
+| `[sf.cmath.assoc.legendre] <https://wg21.link/sf.cmath.assoc.legendre>`_, std::assoc_legendre, None, |Not Started|
+| `[sf.cmath.beta] <https://wg21.link/sf.cmath.beta>`_, std::beta, None, |Not Started|
+| `[sf.cmath.comp.ellint.1] <https://wg21.link/sf.cmath.comp.ellint.1>`_, std::comp_ellint_1, None, |Not Started|
+| `[sf.cmath.comp.ellint.2] <https://wg21.link/sf.cmath.comp.ellint.2>`_, std::comp_ellint_2, None, |Not Started|
+| `[sf.cmath.comp.ellint.3] <https://wg21.link/sf.cmath.comp.ellint.3>`_, std::comp_ellint_3, None, |Not Started|
+| `[sf.cmath.cyl.bessel.i] <https://wg21.link/sf.cmath.cyl.bessel.i>`_, std::cyl_bessel_i, None, |Not Started|
+| `[sf.cmath.cyl.bessel.j] <https://wg21.link/sf.cmath.cyl.bessel.j>`_, std::cyl_bessel_j, None, |Not Started|
+| `[sf.cmath.cyl.bessel.k] <https://wg21.link/sf.cmath.cyl.bessel.k>`_, std::cyl_bessel_k, None, |Not Started|
+| `[sf.cmath.cyl.neumann] <https://wg21.link/sf.cmath.cyl.neumann>`_, std::cyl_neumann, None, |Not Started|
+| `[sf.cmath.ellint.1] <https://wg21.link/sf.cmath.ellint.1>`_, std::ellint_1, None, |Not Started|
+| `[sf.cmath.ellint.2] <https://wg21.link/sf.cmath.ellint.2>`_, std::ellint_2, None, |Not Started|
+| `[sf.cmath.ellint.3] <https://wg21.link/sf.cmath.ellint.3>`_, std::ellint_3, None, |Not Started|
+| `[sf.cmath.expint] <https://wg21.link/sf.cmath.expint>`_, std::expint, None, |Not Started|
+| `[sf.cmath.hermite] <https://wg21.link/sf.cmath.hermite>`_, std::hermite, None, |Complete|
+| `[sf.cmath.laguerre] <https://wg21.link/sf.cmath.laguerre>`_, std::laguerre, None, |Not Started|
+| `[sf.cmath.legendre] <https://wg21.link/sf.cmath.legendre>`_, std::legendre, None, |Not Started|
+| `[sf.cmath.riemann.zeta] <https://wg21.link/sf.cmath.riemann.zeta>`_, std::riemann_zeta, None, |Not Started|
+| `[sf.cmath.sph.bessel] <https://wg21.link/sf.cmath.sph.bessel>`_, std::sph_bessel, None, |Not Started|
+| `[sf.cmath.sph.legendre] <https://wg21.link/sf.cmath.sph.legendre>`_, std::sph_legendre, None, |Not Started|
+| `[sf.cmath.sph.neumann] <https://wg21.link/sf.cmath.sph.neumann>`_, std::sph_neumann, None, |Not Started|

>From fc667d6e28dc4b4ec139d42cc36bb2b1414f879a Mon Sep 17 00:00:00 2001
From: Paul <>
Date: Sun, 28 Apr 2024 15:21:44 +0200
Subject: [PATCH 45/69] 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 690458887460a4..bccae353b0c6bd 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 ca87828caa9ce8ed32203f9ddd9e9203c3e630d9 Mon Sep 17 00:00:00 2001
From: Paul <>
Date: Sun, 28 Apr 2024 15:23:27 +0200
Subject: [PATCH 46/69] 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 f54ffa903f2b97..10f3f75c44c8c3 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 <class _Integer>
 _LIBCPP_HIDE_FROM_ABI std::enable_if_t<std::is_integral_v<_Integer>, 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<double>(__x));
 }
 #endif // _LIBCPP_STD_VER >= 17

>From 3b947d166c12ec210bbb448c4fd69fac9e7efc10 Mon Sep 17 00:00:00 2001
From: Paul <>
Date: Sun, 28 Apr 2024 19:36:20 +0200
Subject: [PATCH 47/69] 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 3000bb7cfa4680..f0ef733fc2c55b 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:
   <http://eel.is/c++draft/print.fun#7>`_. This function is used for other
   ``std::print`` overloads that don't take an ``ostream&`` argument.
 
+`[sf.cmath] <https://wg21.link/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 51f82a50b9007edbb000cfcdcc353dfc28cb8ab2 Mon Sep 17 00:00:00 2001
From: Paul <>
Date: Sun, 28 Apr 2024 22:08:11 +0200
Subject: [PATCH 48/69] 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 10f3f75c44c8c3..677e0a65888875 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 <class _Integer>
-_LIBCPP_HIDE_FROM_ABI std::enable_if_t<std::is_integral_v<_Integer>, double> hermite(unsigned int __n, _Integer __x) {
+template <class _Integer, std::enable_if_t<std::is_integral_v<_Integer>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, _Integer __x) {
   return std::hermite(__n, static_cast<double>(__x));
 }
 #endif // _LIBCPP_STD_VER >= 17

>From 1c99003d0810f817ebbc44e8549e2e847714cf5a Mon Sep 17 00:00:00 2001
From: Paul <>
Date: Sun, 28 Apr 2024 23:05:55 +0200
Subject: [PATCH 49/69] 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 99bfc7da962bdb..48e6e248ff290a 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 <https://https://libcxx.llvm.org/Status/SpecialMath.html>`_.
    .. [#note-P0607] P0607: The parts of P0607 that are not done are the ``<regex>`` bits.
    .. [#note-P0154] P0154: This is currently not implemented for clang because clang does not implement the required macros.
    .. [#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 ea01c9eec14790..694e8a63764079 100644
--- a/libcxx/docs/Status/Cxx17Papers.csv
+++ b/libcxx/docs/Status/Cxx17Papers.csv
@@ -26,7 +26,7 @@
 "`P0013R1 <https://wg21.link/p0013r1>`__","LWG","Logical type traits rev 2","Kona","|Complete|","3.8"
 "","","","","",""
 "`P0024R2 <https://wg21.link/P0024R2>`__","LWG","The Parallelism TS Should be Standardized","Jacksonville","|Partial|",""
-"`P0226R1 <https://wg21.link/P0226R1>`__","LWG","Mathematical Special Functions for C++17","Jacksonville","|In Progress|",""
+"`P0226R1 <https://wg21.link/P0226R1>`__","LWG","Mathematical Special Functions for C++17","Jacksonville","|In Progress| [#note-P0226]_",""
 "`P0220R1 <https://wg21.link/P0220R1>`__","LWG","Adopt Library Fundamentals V1 TS Components for C++17","Jacksonville","|Complete|","16.0"
 "`P0218R1 <https://wg21.link/P0218R1>`__","LWG","Adopt the File System TS for C++17","Jacksonville","|Complete|","7.0"
 "`P0033R1 <https://wg21.link/P0033R1>`__","LWG","Re-enabling shared_from_this","Jacksonville","|Complete|","3.9"

>From 8cf1c8585c95e8eec0315d6b1e6419ed5f63ba0f Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Tue, 30 Apr 2024 20:42:39 +0200
Subject: [PATCH 50/69] 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 4ecd834c5382ae..5c523a56ba9912 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -515,6 +515,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 00000000000000..ee82a76940e4ba
--- /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 <limits>
+
+#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 <class _Real>
+_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<float>(std::hermite(__n, static_cast<double>(__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 <class _Integer, std::enable_if_t<std::is_integral_v<_Integer>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, _Integer __x) {
+  return std::hermite(__n, static_cast<double>(__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 677e0a65888875..acfcb93fb40a4f 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 <limits>
 #include <version>
 
+#include <__math/special_functions.h>
 #include <math.h>
 
 #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 <class _Real>
-_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<float>(std::hermite(__n, static_cast<double>(__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 <class _Integer, std::enable_if_t<std::is_integral_v<_Integer>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, _Integer __x) {
-  return std::hermite(__n, static_cast<double>(__x));
-}
-#endif // _LIBCPP_STD_VER >= 17
-
 #if _LIBCPP_STD_VER >= 20
 template <typename _Fp>
 _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 64652c8307c9e6..1e26ce11e65b0a 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -1486,6 +1486,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 7f003acbf6ea08551450c4b1bb3024b2b8635ded Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Tue, 30 Apr 2024 20:46:14 +0200
Subject: [PATCH 51/69] 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 ee82a76940e4ba..ac2c69c3df85b5 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 <limits>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -34,7 +33,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 template <class _Real>
 _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 7d8c06d72513ed293d731915dfbb50dd001f912d Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Tue, 30 Apr 2024 21:03:17 +0200
Subject: [PATCH 52/69] 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 28045f3290fdd2..fcc9f03e3ae649 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) <https://wg21.link/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 be00c63e6fe3f7..00000000000000
--- a/libcxx/docs/Status/SpecialMathPapers.csv
+++ /dev/null
@@ -1,2 +0,0 @@
-Number,Name,Standard,Assignee,Status,First released version
-`P0226 <https://wg21.link/P0226>`_,"Mathematical Special Functions for C++17","C++17",,"|In Progress|"

>From 62841f461e4c913fcdf43fa737757b1b36d8e3c2 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Tue, 30 Apr 2024 21:05:39 +0200
Subject: [PATCH 53/69] 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 57be6c746c5906..f964e79de91d3c 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] <https://wg21.link/sf.cmath.ellint.2>`_, std::ellint_2, None, |Not Started|
 | `[sf.cmath.ellint.3] <https://wg21.link/sf.cmath.ellint.3>`_, std::ellint_3, None, |Not Started|
 | `[sf.cmath.expint] <https://wg21.link/sf.cmath.expint>`_, std::expint, None, |Not Started|
-| `[sf.cmath.hermite] <https://wg21.link/sf.cmath.hermite>`_, std::hermite, None, |Complete|
+| `[sf.cmath.hermite] <https://wg21.link/sf.cmath.hermite>`_, std::hermite, Paul Xi Cao, |Complete|
 | `[sf.cmath.laguerre] <https://wg21.link/sf.cmath.laguerre>`_, std::laguerre, None, |Not Started|
 | `[sf.cmath.legendre] <https://wg21.link/sf.cmath.legendre>`_, std::legendre, None, |Not Started|
 | `[sf.cmath.riemann.zeta] <https://wg21.link/sf.cmath.riemann.zeta>`_, std::riemann_zeta, None, |Not Started|

>From 71dcd12a17d321d46af15f13e7f9d3ee02604940 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Tue, 30 Apr 2024 21:08:27 +0200
Subject: [PATCH 54/69] 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 397046219bb1fb..8f40839b0c6637 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 <assert_macros.h>
 
-namespace {
-
 inline constexpr unsigned MAX_N = 128;
 
 template <class T>
@@ -283,7 +281,6 @@ void test_hermitel() {
     for (long double x : sample_points<long double>())
       assert(std::hermite(n, x) == std::hermitel(n, x));
 }
-} // namespace
 
 int main(int, char**) {
   test_hermite<float>(1e-5f, 1e-5f);

>From 976309af4d8b289d2b55d9b68437203ed5536618 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Tue, 30 Apr 2024 21:17:04 +0200
Subject: [PATCH 55/69] 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 8f40839b0c6637..b026f48a8267c4 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
+// <cmath>
+
+// 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 <class Integer>
+//    double      hermite( unsigned n, Integer     x);
 
 #include <cassert>
 #include <cmath>

>From b42cd04c8b872c0d05fbbf81824c08ffc7103220 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Tue, 30 Apr 2024 21:17:38 +0200
Subject: [PATCH 56/69] 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 b026f48a8267c4..08500aaa565791 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 <vector>
 #include <array>
 
-#include <assert_macros.h>
-
 inline constexpr unsigned MAX_N = 128;
 
 template <class T>

>From 840321277748f8d62682e6d92420e0b1ac39848e Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Tue, 30 Apr 2024 21:19:48 +0200
Subject: [PATCH 57/69] 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 08500aaa565791..e10cb3b76475a7 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 <class Integer>
 //    double      hermite( unsigned n, Integer     x);
 
+#include <array>
 #include <cassert>
 #include <cmath>
 #include <limits>
 #include <vector>
-#include <array>
 
 inline constexpr unsigned MAX_N = 128;
 

>From 8b57a634c764c2aef653106fbb6b762663f9cf75 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Fri, 3 May 2024 22:05:33 +0200
Subject: [PATCH 58/69] test: refactor/style change. only test<T>() 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 e10cb3b76475a7..7b178b009c8d67 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<T, 7> sample_points() {
   return {-1.0, -0.5, -0.1, 0.0, 0.1, 0.5, 1.0};
 }
 
-template <class T>
-void test_NaN_propagation() {
-  T NaN = std::numeric_limits<T>::quiet_NaN();
-  for (unsigned n = 0; n < MAX_N; ++n)
-    assert(std::isnan(std::hermite(n, NaN)));
-}
-
-template <class T>
-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 <class T>
-struct CompareFloatingValues {
-  T abs_tol;
-  T rel_tol;
+template <class Real>
+class CompareFloatingValues {
+private:
+  Real abs_tol;
+  Real rel_tol;
+
+public:
+  CompareFloatingValues() {
+    abs_tol = []() -> Real {
+      if (std::is_same_v<Real, float>)
+        return 1e-5f;
+      else if (std::is_same_v<Real, double>)
+        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 <class T>
-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<T> 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 <class T>
-void test_recurrence_relation(T x, T abs_tol, T rel_tol) {
-  assert(!std::isnan(x));
-
-  const CompareFloatingValues<T> 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 <class T>
-void test_recurrence_relation(T abs_tol, T rel_tol) {
-  for (T x : sample_points<T>())
-    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<T> 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 <class T>
-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<T>(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 <class Real>
+void test() {
+  { // checks if NaNs are reported correctly (i.e. output == input for input == NaN)
+    using nl = std::numeric_limits<Real>;
+    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<Real>())
+      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<Real>()) {
+      const CompareFloatingValues<Real> 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 <class T>
-void test_hermite(T abs_tol, T rel_tol) {
-  test_NaN_propagation<T>();
+  { // checks std::hermitef for bitwise equality with std::hermite(unsigned, float)
+    if constexpr (std::is_same_v<Real, float>)
+      for (unsigned n = 0; n < MAX_N; ++n)
+        for (float x : sample_points<float>())
+          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<Real, long double>)
+      for (unsigned n = 0; n < MAX_N; ++n)
+        for (long double x : sample_points<long double>())
+          assert(std::hermite(n, x) == std::hermitel(n, x));
+  }
 
-  for (T x : sample_points<T>()) {
-    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<Real>()) {
+      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<Real> 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<Real, float>)
+        return 1e-5f;
+      else if (std::is_same_v<Real, double>)
+        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<Real>(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 <class Integer>
 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<double>(x)));
 }
 
-void test_hermitef() {
-  for (unsigned n = 0; n < MAX_N; ++n)
-    for (float x : sample_points<float>())
-      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<long double>())
-      assert(std::hermite(n, x) == std::hermitel(n, x));
-}
-
-int main(int, char**) {
-  test_hermite<float>(1e-5f, 1e-5f);
-  test_hermite<double>(1e-11, 1e-11);
-  test_hermite<long double>(1e-12l, 1e-12l);
-
-  test_hermitef();
-  test_hermitel();
-
-  test_recurrence_relation<float>(1e-5f, 1e-5f);
-  test_recurrence_relation<double>(1e-11, 1e-11);
-  test_recurrence_relation<long double>(1e-12l, 1e-12l);
-
-  test_roots<float>(1e-5f);
-  test_roots<double>(1e-9);
-  test_roots<long double>(1e-10l);
+int main() {
+  test<float>();
+  test<double>();
+  test<long double>();
 
   test_integers<short>();
   test_integers<int>();
   test_integers<long>();
   test_integers<long long>();
-
-  return 0;
 }

>From 95f2a2498dcaf6117c99c4cc8259f2d570cce6f8 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Fri, 3 May 2024 22:12:41 +0200
Subject: [PATCH 59/69] 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 7b178b009c8d67..5a740af7ae0e93 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 <limits>
 #include <vector>
 
+#include "type_algorithms.h"
+
 inline constexpr unsigned MAX_N = 128;
 
 template <class T>
@@ -287,21 +289,24 @@ void test() {
   }
 }
 
-template <class Integer>
-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<double>(x)));
-}
+struct TestFloat {
+  template <class Real>
+  void operator()() {
+    test<Real>();
+  }
+};
+
+struct TestInt {
+  template <class Integer>
+  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<double>(x)));
+  }
+};
 
 int main() {
-  test<float>();
-  test<double>();
-  test<long double>();
-
-  test_integers<short>();
-  test_integers<int>();
-  test_integers<long>();
-  test_integers<long long>();
+  types::for_each(types::floating_point_types(), TestFloat());
+  types::for_each(types::type_list<short, int, long, long long>(), TestInt());
 }

>From 3ddac0b30dd81aae5482b759de59be269678d36c Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Fri, 3 May 2024 22:30:44 +0200
Subject: [PATCH 60/69] 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 5a740af7ae0e93..32d538eee42c34 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<T> 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 0098ee77a763ea393f0993037e9d93aab2a209c9 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sat, 4 May 2024 13:40:40 +0200
Subject: [PATCH 61/69] 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 32d538eee42c34..5f32158a261f36 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 <class T>
-std::array<T, 7> sample_points() {
-  return {-1.0, -0.5, -0.1, 0.0, 0.1, 0.5, 1.0};
+std::array<T, 11> 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 <class Real>

>From c94fad9ba48a4bb4149ab5cc8f97e1a2a3ac34f4 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sat, 4 May 2024 19:02:30 +0200
Subject: [PATCH 62/69] 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 5f32158a261f36..f718ff30b1b7d7 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<Real>::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<Real>::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 511b45679ab65dc3efca81abc976c27711a5df9a Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sat, 4 May 2024 19:04:06 +0200
Subject: [PATCH 63/69] 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 ac2c69c3df85b5..60ad6e173e4179 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 <limits>
 
 #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 84b7b87e968831265f000f008016fbfd3473f258 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sat, 4 May 2024 19:13:25 +0200
Subject: [PATCH 64/69] index.rst: add special math status page to TOC

---
 libcxx/docs/index.rst | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libcxx/docs/index.rst b/libcxx/docs/index.rst
index 743f99297d17d2..621057b9605d06 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
 
 
@@ -71,7 +72,7 @@ iOS, watchOS, and tvOS, Google Search, the Android operating system, and FreeBSD
 user base of over 1 billion daily active users.
 
 Since its inception, libc++ has focused on delivering high performance, standards-conformance, and portability. It has
-been extensively tested and optimized, making it robust and production ready. libc++ fully implements C++11 and C++14, 
+been extensively tested and optimized, making it robust and production ready. libc++ fully implements C++11 and C++14,
 with C++17, C++20, C++23, and C++26 features being actively developed and making steady progress.
 
 libc++ is continuously integrated and tested on a wide range of platforms and configurations, ensuring its reliability

>From 6b28fc59cc674f15075ec058ac6e3b1b217747bc Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sat, 4 May 2024 19:16:52 +0200
Subject: [PATCH 65/69] 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 0fe887447ad850..eaa07bba561a95 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 58ff841509fefa04784d788af4b8e6f18c84d5dd Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sat, 4 May 2024 19:23:21 +0200
Subject: [PATCH 66/69] 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 acfcb93fb40a4f..60dca1453dd812 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 <class Integer>
+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 492c4c8e3574f787b0d5f07e66502799052f2cd1 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sat, 4 May 2024 20:37:13 +0200
Subject: [PATCH 67/69] 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 60dca1453dd812..c53dc1050fda78 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 <class Integer>
 double         hermite(unsigned n, Integer x);                   // C++17
 

>From 67b0da98f2a62422683135a61cd4e14f56770582 Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sat, 4 May 2024 20:40:28 +0200
Subject: [PATCH 68/69] 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 f718ff30b1b7d7..b3ab7f2d58895a 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
+
 // <cmath>
 
-// 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 <class Integer>
-//    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 <class Integer>
+// double         hermite(unsigned n, Integer x);
 
 #include <array>
 #include <cassert>

>From d4ea6088dca10dde0cfc21ad25ec3df218955c8c Mon Sep 17 00:00:00 2001
From: Paul <{ID}+{username}@users.noreply.github.com>
Date: Sat, 4 May 2024 20:56:00 +0200
Subject: [PATCH 69/69] 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 60ad6e173e4179..7e30e5e750be3e 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 <class _Real>
 _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 <class _Integer, std::enable_if_t<std::is_integral_v<_Integer>, int> =
 _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, _Integer __x) {
   return std::hermite(__n, static_cast<double>(__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 b3ab7f2d58895a..e5d7b42fe28fa4 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 <class T>
 std::vector<T> get_roots(unsigned n) {
   switch (n) {



More information about the libcxx-commits mailing list