Skip to content

Commit af0d731

Browse files
authored
[libc++][math] Mathematical Special Functions: Hermite Polynomial (#89982)
Implementing the Hermite polynomials which are part of C++17's mathematical special functions. The goal is to get early feedback which will make implementing the other functions easier. Integration of functions in chunks (e.g. `std::hermite` at first, then `std::laguerre`, etc.) might make sense as well (also see note on boost.math below). I started out from this abandoned merge request: https://reviews.llvm.org/D58876 . The C++23 standard defines them in-terms of `/* floating-point type */` arguments. I have not looked into that. Note, there is still an ongoing discussion on discourse whether importing boost.math is an option.
1 parent 5303ca1 commit af0d731

File tree

13 files changed

+516
-1
lines changed

13 files changed

+516
-1
lines changed

libcxx/docs/ImplementationDefinedBehavior.rst

+11
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,17 @@ Libc++ determines that a stream is Unicode-capable terminal by:
5151
<http://eel.is/c++draft/print.fun#7>`_. This function is used for other
5252
``std::print`` overloads that don't take an ``ostream&`` argument.
5353

54+
`[sf.cmath] <https://wg21.link/sf.cmath>`_ Mathematical Special Functions: Large indices
55+
----------------------------------------------------------------------------------------
56+
57+
Most functions within the Mathematical Special Functions section contain integral indices.
58+
The Standard specifies the result for larger indices as implementation-defined.
59+
Libc++ pursuits reasonable results by choosing the same formulas as for indices below that threshold.
60+
E.g.
61+
62+
- ``std::hermite(unsigned n, T x)`` for ``n >= 128``
63+
64+
5465
Listed in the index of implementation-defined behavior
5566
======================================================
5667

libcxx/docs/Status/Cxx17.rst

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ Paper Status
4141
.. note::
4242

4343
.. [#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``.
44+
.. [#note-P0226] P0226: Progress is tracked `here <https://https://libcxx.llvm.org/Status/SpecialMath.html>`_.
4445
.. [#note-P0607] P0607: The parts of P0607 that are not done are the ``<regex>`` bits.
4546
.. [#note-P0154] P0154: The required macros are only implemented as of clang 19.
4647
.. [#note-P0452] P0452: The changes to ``std::transform_inclusive_scan`` and ``std::transform_exclusive_scan`` have not yet been implemented.

libcxx/docs/Status/Cxx17Papers.csv

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"`P0013R1 <https://wg21.link/p0013r1>`__","LWG","Logical type traits rev 2","Kona","|Complete|","3.8"
2727
"","","","","",""
2828
"`P0024R2 <https://wg21.link/P0024R2>`__","LWG","The Parallelism TS Should be Standardized","Jacksonville","|Partial|",""
29-
"`P0226R1 <https://wg21.link/P0226R1>`__","LWG","Mathematical Special Functions for C++17","Jacksonville","",""
29+
"`P0226R1 <https://wg21.link/P0226R1>`__","LWG","Mathematical Special Functions for C++17","Jacksonville","|In Progress| [#note-P0226]_",""
3030
"`P0220R1 <https://wg21.link/P0220R1>`__","LWG","Adopt Library Fundamentals V1 TS Components for C++17","Jacksonville","|Complete|","16.0"
3131
"`P0218R1 <https://wg21.link/P0218R1>`__","LWG","Adopt the File System TS for C++17","Jacksonville","|Complete|","7.0"
3232
"`P0033R1 <https://wg21.link/P0033R1>`__","LWG","Re-enabling shared_from_this","Jacksonville","|Complete|","3.9"

libcxx/docs/Status/SpecialMath.rst

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
.. special-math-status:
2+
3+
======================================================
4+
libc++ Mathematical Special Functions Status (P0226R1)
5+
======================================================
6+
7+
.. include:: ../Helpers/Styles.rst
8+
9+
.. contents::
10+
:local:
11+
12+
Overview
13+
========
14+
15+
This document contains the status of the C++17 mathematical special functions implementation in libc++.
16+
It is used to track both the status of the sub-projects of the effort and who is assigned to these sub-projects.
17+
This avoids duplicating effort.
18+
19+
If you are interested in contributing to this effort, please send a message
20+
to the #libcxx channel in the LLVM discord. Please *do not* start working
21+
on any items below that has already been assigned to someone else.
22+
23+
Sub-projects in the Implementation Effort
24+
=========================================
25+
26+
.. csv-table::
27+
:file: SpecialMathProjects.csv
28+
:header-rows: 1
29+
:widths: auto
30+
31+
Paper and Issue Status
32+
======================
33+
34+
The underlying paper is `Mathematical Special Functions for C++17 (P0226) <https://wg21.link/P0226>`_ and is included in C++17.
35+
Implementation is *In Progress*.
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Section,Description,Assignee,Complete
2+
| `[sf.cmath.assoc.laguerre] <https://wg21.link/sf.cmath.assoc.laguerre>`_, std::assoc_laguerre, None, |Not Started|
3+
| `[sf.cmath.assoc.legendre] <https://wg21.link/sf.cmath.assoc.legendre>`_, std::assoc_legendre, None, |Not Started|
4+
| `[sf.cmath.beta] <https://wg21.link/sf.cmath.beta>`_, std::beta, None, |Not Started|
5+
| `[sf.cmath.comp.ellint.1] <https://wg21.link/sf.cmath.comp.ellint.1>`_, std::comp_ellint_1, None, |Not Started|
6+
| `[sf.cmath.comp.ellint.2] <https://wg21.link/sf.cmath.comp.ellint.2>`_, std::comp_ellint_2, None, |Not Started|
7+
| `[sf.cmath.comp.ellint.3] <https://wg21.link/sf.cmath.comp.ellint.3>`_, std::comp_ellint_3, None, |Not Started|
8+
| `[sf.cmath.cyl.bessel.i] <https://wg21.link/sf.cmath.cyl.bessel.i>`_, std::cyl_bessel_i, None, |Not Started|
9+
| `[sf.cmath.cyl.bessel.j] <https://wg21.link/sf.cmath.cyl.bessel.j>`_, std::cyl_bessel_j, None, |Not Started|
10+
| `[sf.cmath.cyl.bessel.k] <https://wg21.link/sf.cmath.cyl.bessel.k>`_, std::cyl_bessel_k, None, |Not Started|
11+
| `[sf.cmath.cyl.neumann] <https://wg21.link/sf.cmath.cyl.neumann>`_, std::cyl_neumann, None, |Not Started|
12+
| `[sf.cmath.ellint.1] <https://wg21.link/sf.cmath.ellint.1>`_, std::ellint_1, None, |Not Started|
13+
| `[sf.cmath.ellint.2] <https://wg21.link/sf.cmath.ellint.2>`_, std::ellint_2, None, |Not Started|
14+
| `[sf.cmath.ellint.3] <https://wg21.link/sf.cmath.ellint.3>`_, std::ellint_3, None, |Not Started|
15+
| `[sf.cmath.expint] <https://wg21.link/sf.cmath.expint>`_, std::expint, None, |Not Started|
16+
| `[sf.cmath.hermite] <https://wg21.link/sf.cmath.hermite>`_, std::hermite, Paul Xi Cao, |Complete|
17+
| `[sf.cmath.laguerre] <https://wg21.link/sf.cmath.laguerre>`_, std::laguerre, None, |Not Started|
18+
| `[sf.cmath.legendre] <https://wg21.link/sf.cmath.legendre>`_, std::legendre, None, |Not Started|
19+
| `[sf.cmath.riemann.zeta] <https://wg21.link/sf.cmath.riemann.zeta>`_, std::riemann_zeta, None, |Not Started|
20+
| `[sf.cmath.sph.bessel] <https://wg21.link/sf.cmath.sph.bessel>`_, std::sph_bessel, None, |Not Started|
21+
| `[sf.cmath.sph.legendre] <https://wg21.link/sf.cmath.sph.legendre>`_, std::sph_legendre, None, |Not Started|
22+
| `[sf.cmath.sph.neumann] <https://wg21.link/sf.cmath.sph.neumann>`_, std::sph_neumann, None, |Not Started|

libcxx/docs/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ Getting Started with libc++
5353
Status/PSTL
5454
Status/Ranges
5555
Status/Spaceship
56+
Status/SpecialMath
5657
Status/Zip
5758

5859

libcxx/include/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,7 @@ set(files
509509
__math/remainder.h
510510
__math/roots.h
511511
__math/rounding_functions.h
512+
__math/special_functions.h
512513
__math/traits.h
513514
__math/trigonometric_functions.h
514515
__mbstate_t.h
+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef _LIBCPP___MATH_SPECIAL_FUNCTIONS_H
11+
#define _LIBCPP___MATH_SPECIAL_FUNCTIONS_H
12+
13+
#include <__config>
14+
#include <__math/copysign.h>
15+
#include <__math/traits.h>
16+
#include <__type_traits/enable_if.h>
17+
#include <__type_traits/is_integral.h>
18+
#include <limits>
19+
20+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
21+
# pragma GCC system_header
22+
#endif
23+
24+
_LIBCPP_BEGIN_NAMESPACE_STD
25+
26+
#if _LIBCPP_STD_VER >= 17
27+
28+
template <class _Real>
29+
_LIBCPP_HIDE_FROM_ABI _Real __hermite(unsigned __n, _Real __x) {
30+
// The Hermite polynomial H_n(x).
31+
// The implementation is based on the recurrence formula: H_{n+1}(x) = 2x H_n(x) - 2n H_{n-1}.
32+
// Press, William H., et al. Numerical recipes 3rd edition: The art of scientific computing.
33+
// Cambridge university press, 2007, p. 183.
34+
35+
// NOLINTBEGIN(readability-identifier-naming)
36+
if (__math::isnan(__x))
37+
return __x;
38+
39+
_Real __H_0{1};
40+
if (__n == 0)
41+
return __H_0;
42+
43+
_Real __H_n_prev = __H_0;
44+
_Real __H_n = 2 * __x;
45+
for (unsigned __i = 1; __i < __n; ++__i) {
46+
_Real __H_n_next = 2 * (__x * __H_n - __i * __H_n_prev);
47+
__H_n_prev = __H_n;
48+
__H_n = __H_n_next;
49+
}
50+
51+
if (!__math::isfinite(__H_n)) {
52+
// Overflow occured. Two possible cases:
53+
// n is odd: return infinity of the same sign as x.
54+
// n is even: return +Inf
55+
_Real __inf = std::numeric_limits<_Real>::infinity();
56+
return (__n & 1) ? __math::copysign(__inf, __x) : __inf;
57+
}
58+
return __H_n;
59+
// NOLINTEND(readability-identifier-naming)
60+
}
61+
62+
inline _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, double __x) { return std::__hermite(__n, __x); }
63+
64+
inline _LIBCPP_HIDE_FROM_ABI float hermite(unsigned __n, float __x) {
65+
// use double internally -- float is too prone to overflow!
66+
return static_cast<float>(std::hermite(__n, static_cast<double>(__x)));
67+
}
68+
69+
inline _LIBCPP_HIDE_FROM_ABI long double hermite(unsigned __n, long double __x) { return std::__hermite(__n, __x); }
70+
71+
inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __n, float __x) { return std::hermite(__n, __x); }
72+
73+
inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __n, long double __x) { return std::hermite(__n, __x); }
74+
75+
template <class _Integer, std::enable_if_t<std::is_integral_v<_Integer>, int> = 0>
76+
_LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, _Integer __x) {
77+
return std::hermite(__n, static_cast<double>(__x));
78+
}
79+
80+
#endif // _LIBCPP_STD_VER >= 17
81+
82+
_LIBCPP_END_NAMESPACE_STD
83+
84+
#endif // _LIBCPP___MATH_SPECIAL_FUNCTIONS_H

libcxx/include/cmath

+9
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,14 @@ floating_point fmin (arithmetic x, arithmetic y);
204204
float fminf(float x, float y);
205205
long double fminl(long double x, long double y);
206206
207+
double hermite(unsigned n, double x); // C++17
208+
float hermite(unsigned n, float x); // C++17
209+
long double hermite(unsigned n, long double x); // C++17
210+
float hermitef(unsigned n, float x); // C++17
211+
long double hermitel(unsigned n, long double x); // C++17
212+
template <class Integer>
213+
double hermite(unsigned n, Integer x); // C++17
214+
207215
floating_point hypot (arithmetic x, arithmetic y);
208216
float hypotf(float x, float y);
209217
long double hypotl(long double x, long double y);
@@ -315,6 +323,7 @@ constexpr long double lerp(long double a, long double b, long double t) noexcept
315323
#include <limits>
316324
#include <version>
317325

326+
#include <__math/special_functions.h>
318327
#include <math.h>
319328

320329
#ifndef _LIBCPP_MATH_H

libcxx/include/module.modulemap

+1
Original file line numberDiff line numberDiff line change
@@ -1485,6 +1485,7 @@ module std_private_math_modulo [system] { header "__mat
14851485
module std_private_math_remainder [system] { header "__math/remainder.h" }
14861486
module std_private_math_roots [system] { header "__math/roots.h" }
14871487
module std_private_math_rounding_functions [system] { header "__math/rounding_functions.h" }
1488+
module std_private_math_special_functions [system] { header "__math/special_functions.h" }
14881489
module std_private_math_traits [system] { header "__math/traits.h" }
14891490
module std_private_math_trigonometric_functions [system] { header "__math/trigonometric_functions.h" }
14901491

libcxx/modules/std/cmath.inc

+2
Original file line numberDiff line numberDiff line change
@@ -334,12 +334,14 @@ export namespace std {
334334
using std::expint;
335335
using std::expintf;
336336
using std::expintl;
337+
#endif
337338

338339
// [sf.cmath.hermite], Hermite polynomials
339340
using std::hermite;
340341
using std::hermitef;
341342
using std::hermitel;
342343

344+
#if 0
343345
// [sf.cmath.laguerre], Laguerre polynomials
344346
using std::laguerre;
345347
using std::laguerref;

0 commit comments

Comments
 (0)