xref: /llvm-project/libcxx/test/std/numerics/c.math/hermite.pass.cpp (revision f343fee8c5c9526b3cf62ee6d450c44b69a47e87)
1af0d731bSPaulXiCao //===----------------------------------------------------------------------===//
2af0d731bSPaulXiCao //
3af0d731bSPaulXiCao // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4af0d731bSPaulXiCao // See https://llvm.org/LICENSE.txt for license information.
5af0d731bSPaulXiCao // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6af0d731bSPaulXiCao //
7af0d731bSPaulXiCao //===----------------------------------------------------------------------===//
8af0d731bSPaulXiCao 
9af0d731bSPaulXiCao // UNSUPPORTED: c++03, c++11, c++14
10af0d731bSPaulXiCao 
11af0d731bSPaulXiCao // <cmath>
12af0d731bSPaulXiCao 
13af0d731bSPaulXiCao // double         hermite(unsigned n, double x);
14af0d731bSPaulXiCao // float          hermite(unsigned n, float x);
15af0d731bSPaulXiCao // long double    hermite(unsigned n, long double x);
16af0d731bSPaulXiCao // float          hermitef(unsigned n, float x);
17af0d731bSPaulXiCao // long double    hermitel(unsigned n, long double x);
18af0d731bSPaulXiCao // template <class Integer>
19af0d731bSPaulXiCao // double         hermite(unsigned n, Integer x);
20af0d731bSPaulXiCao 
21af0d731bSPaulXiCao #include <array>
22af0d731bSPaulXiCao #include <cassert>
23af0d731bSPaulXiCao #include <cmath>
24af0d731bSPaulXiCao #include <limits>
25af0d731bSPaulXiCao #include <vector>
26af0d731bSPaulXiCao 
27af0d731bSPaulXiCao #include "type_algorithms.h"
28af0d731bSPaulXiCao 
29*f343fee8SZibi Sarbinowski template <class Real>
30*f343fee8SZibi Sarbinowski constexpr unsigned get_maximal_order() {
31*f343fee8SZibi Sarbinowski   if constexpr (std::numeric_limits<Real>::is_iec559)
32*f343fee8SZibi Sarbinowski     return 128;
33*f343fee8SZibi Sarbinowski   else { // Workaround for z/OS HexFloat.
34*f343fee8SZibi Sarbinowski     // Note |H_n(x)| < 10^75 for n < 39 and x in sample_points().
35*f343fee8SZibi Sarbinowski     static_assert(std::numeric_limits<Real>::max_exponent10 == 75);
36*f343fee8SZibi Sarbinowski     return 39;
37*f343fee8SZibi Sarbinowski   }
38*f343fee8SZibi Sarbinowski }
39af0d731bSPaulXiCao 
40af0d731bSPaulXiCao template <class T>
41af0d731bSPaulXiCao std::array<T, 11> sample_points() {
42af0d731bSPaulXiCao   return {-12.34, -7.42, -1.0, -0.5, -0.1, 0.0, 0.1, 0.5, 1.0, 5.67, 15.67};
43af0d731bSPaulXiCao }
44af0d731bSPaulXiCao 
45af0d731bSPaulXiCao template <class Real>
46af0d731bSPaulXiCao class CompareFloatingValues {
47af0d731bSPaulXiCao private:
48af0d731bSPaulXiCao   Real abs_tol;
49af0d731bSPaulXiCao   Real rel_tol;
50af0d731bSPaulXiCao 
51af0d731bSPaulXiCao public:
52af0d731bSPaulXiCao   CompareFloatingValues() {
53af0d731bSPaulXiCao     abs_tol = []() -> Real {
54af0d731bSPaulXiCao       if (std::is_same_v<Real, float>)
55af0d731bSPaulXiCao         return 1e-5f;
56af0d731bSPaulXiCao       else if (std::is_same_v<Real, double>)
57af0d731bSPaulXiCao         return 1e-11;
58af0d731bSPaulXiCao       else
59af0d731bSPaulXiCao         return 1e-12l;
60af0d731bSPaulXiCao     }();
61af0d731bSPaulXiCao 
62af0d731bSPaulXiCao     rel_tol = abs_tol;
63af0d731bSPaulXiCao   }
64af0d731bSPaulXiCao 
65af0d731bSPaulXiCao   bool operator()(Real result, Real expected) const {
66af0d731bSPaulXiCao     if (std::isinf(expected) && std::isinf(result))
67af0d731bSPaulXiCao       return result == expected;
68af0d731bSPaulXiCao 
69af0d731bSPaulXiCao     if (std::isnan(expected) || std::isnan(result))
70af0d731bSPaulXiCao       return false;
71af0d731bSPaulXiCao 
72af0d731bSPaulXiCao     Real tol = abs_tol + std::abs(expected) * rel_tol;
73af0d731bSPaulXiCao     return std::abs(result - expected) < tol;
74af0d731bSPaulXiCao   }
75af0d731bSPaulXiCao };
76af0d731bSPaulXiCao 
77af0d731bSPaulXiCao // Roots are taken from
78af0d731bSPaulXiCao // Salzer, Herbert E., Ruth Zucker, and Ruth Capuano.
79af0d731bSPaulXiCao // Table of the zeros and weight factors of the first twenty Hermite
80af0d731bSPaulXiCao // polynomials. US Government Printing Office, 1952.
81af0d731bSPaulXiCao template <class T>
82af0d731bSPaulXiCao std::vector<T> get_roots(unsigned n) {
83af0d731bSPaulXiCao   switch (n) {
84af0d731bSPaulXiCao   case 0:
85af0d731bSPaulXiCao     return {};
86af0d731bSPaulXiCao   case 1:
87af0d731bSPaulXiCao     return {T(0)};
88af0d731bSPaulXiCao   case 2:
89af0d731bSPaulXiCao     return {T(0.707106781186548)};
90af0d731bSPaulXiCao   case 3:
91af0d731bSPaulXiCao     return {T(0), T(1.224744871391589)};
92af0d731bSPaulXiCao   case 4:
93af0d731bSPaulXiCao     return {T(0.524647623275290), T(1.650680123885785)};
94af0d731bSPaulXiCao   case 5:
95af0d731bSPaulXiCao     return {T(0), T(0.958572464613819), T(2.020182870456086)};
96af0d731bSPaulXiCao   case 6:
97af0d731bSPaulXiCao     return {T(0.436077411927617), T(1.335849074013697), T(2.350604973674492)};
98af0d731bSPaulXiCao   case 7:
99af0d731bSPaulXiCao     return {T(0), T(0.816287882858965), T(1.673551628767471), T(2.651961356835233)};
100af0d731bSPaulXiCao   case 8:
101af0d731bSPaulXiCao     return {T(0.381186990207322), T(1.157193712446780), T(1.981656756695843), T(2.930637420257244)};
102af0d731bSPaulXiCao   case 9:
103af0d731bSPaulXiCao     return {T(0), T(0.723551018752838), T(1.468553289216668), T(2.266580584531843), T(3.190993201781528)};
104af0d731bSPaulXiCao   case 10:
105af0d731bSPaulXiCao     return {
106af0d731bSPaulXiCao         T(0.342901327223705), T(1.036610829789514), T(1.756683649299882), T(2.532731674232790), T(3.436159118837738)};
107af0d731bSPaulXiCao   case 11:
108af0d731bSPaulXiCao     return {T(0),
109af0d731bSPaulXiCao             T(0.65680956682100),
110af0d731bSPaulXiCao             T(1.326557084494933),
111af0d731bSPaulXiCao             T(2.025948015825755),
112af0d731bSPaulXiCao             T(2.783290099781652),
113af0d731bSPaulXiCao             T(3.668470846559583)};
114af0d731bSPaulXiCao 
115af0d731bSPaulXiCao   case 12:
116af0d731bSPaulXiCao     return {T(0.314240376254359),
117af0d731bSPaulXiCao             T(0.947788391240164),
118af0d731bSPaulXiCao             T(1.597682635152605),
119af0d731bSPaulXiCao             T(2.279507080501060),
120af0d731bSPaulXiCao             T(3.020637025120890),
121af0d731bSPaulXiCao             T(3.889724897869782)};
122af0d731bSPaulXiCao 
123af0d731bSPaulXiCao   case 13:
124af0d731bSPaulXiCao     return {T(0),
125af0d731bSPaulXiCao             T(0.605763879171060),
126af0d731bSPaulXiCao             T(1.220055036590748),
127af0d731bSPaulXiCao             T(1.853107651601512),
128af0d731bSPaulXiCao             T(2.519735685678238),
129af0d731bSPaulXiCao             T(3.246608978372410),
130af0d731bSPaulXiCao             T(4.101337596178640)};
131af0d731bSPaulXiCao 
132af0d731bSPaulXiCao   case 14:
133af0d731bSPaulXiCao     return {T(0.29174551067256),
134af0d731bSPaulXiCao             T(0.87871378732940),
135af0d731bSPaulXiCao             T(1.47668273114114),
136af0d731bSPaulXiCao             T(2.09518325850772),
137af0d731bSPaulXiCao             T(2.74847072498540),
138af0d731bSPaulXiCao             T(3.46265693360227),
139af0d731bSPaulXiCao             T(4.30444857047363)};
140af0d731bSPaulXiCao 
141af0d731bSPaulXiCao   case 15:
142af0d731bSPaulXiCao     return {T(0.00000000000000),
143af0d731bSPaulXiCao             T(0.56506958325558),
144af0d731bSPaulXiCao             T(1.13611558521092),
145af0d731bSPaulXiCao             T(1.71999257518649),
146af0d731bSPaulXiCao             T(2.32573248617386),
147af0d731bSPaulXiCao             T(2.96716692790560),
148af0d731bSPaulXiCao             T(3.66995037340445),
149af0d731bSPaulXiCao             T(4.49999070730939)};
150af0d731bSPaulXiCao 
151af0d731bSPaulXiCao   case 16:
152af0d731bSPaulXiCao     return {T(0.27348104613815),
153af0d731bSPaulXiCao             T(0.82295144914466),
154af0d731bSPaulXiCao             T(1.38025853919888),
155af0d731bSPaulXiCao             T(1.95178799091625),
156af0d731bSPaulXiCao             T(2.54620215784748),
157af0d731bSPaulXiCao             T(3.17699916197996),
158af0d731bSPaulXiCao             T(3.86944790486012),
159af0d731bSPaulXiCao             T(4.68873893930582)};
160af0d731bSPaulXiCao 
161af0d731bSPaulXiCao   case 17:
162af0d731bSPaulXiCao     return {T(0),
163af0d731bSPaulXiCao             T(0.5316330013427),
164af0d731bSPaulXiCao             T(1.0676487257435),
165af0d731bSPaulXiCao             T(1.6129243142212),
166af0d731bSPaulXiCao             T(2.1735028266666),
167af0d731bSPaulXiCao             T(2.7577629157039),
168af0d731bSPaulXiCao             T(3.3789320911415),
169af0d731bSPaulXiCao             T(4.0619466758755),
170af0d731bSPaulXiCao             T(4.8713451936744)};
171af0d731bSPaulXiCao 
172af0d731bSPaulXiCao   case 18:
173af0d731bSPaulXiCao     return {T(0.2582677505191),
174af0d731bSPaulXiCao             T(0.7766829192674),
175af0d731bSPaulXiCao             T(1.3009208583896),
176af0d731bSPaulXiCao             T(1.8355316042616),
177af0d731bSPaulXiCao             T(2.3862990891667),
178af0d731bSPaulXiCao             T(2.9613775055316),
179af0d731bSPaulXiCao             T(3.5737690684863),
180af0d731bSPaulXiCao             T(4.2481178735681),
181af0d731bSPaulXiCao             T(5.0483640088745)};
182af0d731bSPaulXiCao 
183af0d731bSPaulXiCao   case 19:
184af0d731bSPaulXiCao     return {T(0),
185af0d731bSPaulXiCao             T(0.5035201634239),
186af0d731bSPaulXiCao             T(1.0103683871343),
187af0d731bSPaulXiCao             T(1.5241706193935),
188af0d731bSPaulXiCao             T(2.0492317098506),
189af0d731bSPaulXiCao             T(2.5911337897945),
190af0d731bSPaulXiCao             T(3.1578488183476),
191af0d731bSPaulXiCao             T(3.7621873519640),
192af0d731bSPaulXiCao             T(4.4285328066038),
193af0d731bSPaulXiCao             T(5.2202716905375)};
194af0d731bSPaulXiCao 
195af0d731bSPaulXiCao   case 20:
196af0d731bSPaulXiCao     return {T(0.2453407083009),
197af0d731bSPaulXiCao             T(0.7374737285454),
198af0d731bSPaulXiCao             T(1.2340762153953),
199af0d731bSPaulXiCao             T(1.7385377121166),
200af0d731bSPaulXiCao             T(2.2549740020893),
201af0d731bSPaulXiCao             T(2.7888060584281),
202af0d731bSPaulXiCao             T(3.347854567332),
203af0d731bSPaulXiCao             T(3.9447640401156),
204af0d731bSPaulXiCao             T(4.6036824495507),
205af0d731bSPaulXiCao             T(5.3874808900112)};
206af0d731bSPaulXiCao 
207af0d731bSPaulXiCao   default: // polynom degree n>20 is unsupported
208af0d731bSPaulXiCao     assert(false);
209af0d731bSPaulXiCao     return {T(-42)};
210af0d731bSPaulXiCao   }
211af0d731bSPaulXiCao }
212af0d731bSPaulXiCao 
213af0d731bSPaulXiCao template <class Real>
214af0d731bSPaulXiCao void test() {
215*f343fee8SZibi Sarbinowski   if constexpr (
216*f343fee8SZibi Sarbinowski       std::numeric_limits<Real>::has_quiet_NaN &&
217*f343fee8SZibi Sarbinowski       std::numeric_limits<
218*f343fee8SZibi Sarbinowski           Real>::has_signaling_NaN) { // checks if NaNs are reported correctly (i.e. output == input for input == NaN)
219af0d731bSPaulXiCao     using nl = std::numeric_limits<Real>;
220af0d731bSPaulXiCao     for (Real NaN : {nl::quiet_NaN(), nl::signaling_NaN()})
221*f343fee8SZibi Sarbinowski       for (unsigned n = 0; n < get_maximal_order<Real>(); ++n)
222af0d731bSPaulXiCao         assert(std::isnan(std::hermite(n, NaN)));
223af0d731bSPaulXiCao   }
224af0d731bSPaulXiCao 
225*f343fee8SZibi Sarbinowski   if constexpr (std::numeric_limits<Real>::has_quiet_NaN &&
226*f343fee8SZibi Sarbinowski                 std::numeric_limits<
227*f343fee8SZibi Sarbinowski                     Real>::has_signaling_NaN) { // simple sample points for n=0..127 should not produce NaNs.
228af0d731bSPaulXiCao     for (Real x : sample_points<Real>())
229*f343fee8SZibi Sarbinowski       for (unsigned n = 0; n < get_maximal_order<Real>(); ++n)
230af0d731bSPaulXiCao         assert(!std::isnan(std::hermite(n, x)));
231af0d731bSPaulXiCao   }
232af0d731bSPaulXiCao 
233af0d731bSPaulXiCao   { // checks std::hermite(n, x) for n=0..5 against analytic polynoms
234af0d731bSPaulXiCao     const auto h0 = [](Real) -> Real { return 1; };
235af0d731bSPaulXiCao     const auto h1 = [](Real y) -> Real { return 2 * y; };
236af0d731bSPaulXiCao     const auto h2 = [](Real y) -> Real { return 4 * y * y - 2; };
237af0d731bSPaulXiCao     const auto h3 = [](Real y) -> Real { return y * (8 * y * y - 12); };
238af0d731bSPaulXiCao     const auto h4 = [](Real y) -> Real { return (16 * std::pow(y, 4) - 48 * y * y + 12); };
239af0d731bSPaulXiCao     const auto h5 = [](Real y) -> Real { return y * (32 * std::pow(y, 4) - 160 * y * y + 120); };
240af0d731bSPaulXiCao 
241af0d731bSPaulXiCao     for (Real x : sample_points<Real>()) {
242af0d731bSPaulXiCao       const CompareFloatingValues<Real> compare;
243af0d731bSPaulXiCao       assert(compare(std::hermite(0, x), h0(x)));
244af0d731bSPaulXiCao       assert(compare(std::hermite(1, x), h1(x)));
245af0d731bSPaulXiCao       assert(compare(std::hermite(2, x), h2(x)));
246af0d731bSPaulXiCao       assert(compare(std::hermite(3, x), h3(x)));
247af0d731bSPaulXiCao       assert(compare(std::hermite(4, x), h4(x)));
248af0d731bSPaulXiCao       assert(compare(std::hermite(5, x), h5(x)));
249af0d731bSPaulXiCao     }
250af0d731bSPaulXiCao   }
251af0d731bSPaulXiCao 
252af0d731bSPaulXiCao   { // checks std::hermitef for bitwise equality with std::hermite(unsigned, float)
253af0d731bSPaulXiCao     if constexpr (std::is_same_v<Real, float>)
254*f343fee8SZibi Sarbinowski       for (unsigned n = 0; n < get_maximal_order<Real>(); ++n)
255af0d731bSPaulXiCao         for (float x : sample_points<float>())
256af0d731bSPaulXiCao           assert(std::hermite(n, x) == std::hermitef(n, x));
257af0d731bSPaulXiCao   }
258af0d731bSPaulXiCao 
259af0d731bSPaulXiCao   { // checks std::hermitel for bitwise equality with std::hermite(unsigned, long double)
260af0d731bSPaulXiCao     if constexpr (std::is_same_v<Real, long double>)
261*f343fee8SZibi Sarbinowski       for (unsigned n = 0; n < get_maximal_order<Real>(); ++n)
262af0d731bSPaulXiCao         for (long double x : sample_points<long double>())
263af0d731bSPaulXiCao           assert(std::hermite(n, x) == std::hermitel(n, x));
264af0d731bSPaulXiCao   }
265af0d731bSPaulXiCao 
266af0d731bSPaulXiCao   { // Checks if the characteristic recurrence relation holds:    H_{n+1}(x) = 2x H_n(x) - 2n H_{n-1}(x)
267af0d731bSPaulXiCao     for (Real x : sample_points<Real>()) {
268*f343fee8SZibi Sarbinowski       for (unsigned n = 1; n < get_maximal_order<Real>() - 1; ++n) {
269af0d731bSPaulXiCao         Real H_next            = std::hermite(n + 1, x);
270af0d731bSPaulXiCao         Real H_next_recurrence = 2 * (x * std::hermite(n, x) - n * std::hermite(n - 1, x));
271af0d731bSPaulXiCao 
272af0d731bSPaulXiCao         if (std::isinf(H_next))
273af0d731bSPaulXiCao           break;
274af0d731bSPaulXiCao         const CompareFloatingValues<Real> compare;
275af0d731bSPaulXiCao         assert(compare(H_next, H_next_recurrence));
276af0d731bSPaulXiCao       }
277af0d731bSPaulXiCao     }
278af0d731bSPaulXiCao   }
279af0d731bSPaulXiCao 
280af0d731bSPaulXiCao   { // sanity checks: hermite polynoms need to change signs at (simple) roots. checked upto order n<=20.
281af0d731bSPaulXiCao 
282af0d731bSPaulXiCao     // root tolerance: must be smaller than the smallest difference between adjacent roots
283af0d731bSPaulXiCao     Real tol = []() -> Real {
284af0d731bSPaulXiCao       if (std::is_same_v<Real, float>)
285af0d731bSPaulXiCao         return 1e-5f;
286af0d731bSPaulXiCao       else if (std::is_same_v<Real, double>)
287af0d731bSPaulXiCao         return 1e-9;
288af0d731bSPaulXiCao       else
289af0d731bSPaulXiCao         return 1e-10l;
290af0d731bSPaulXiCao     }();
291af0d731bSPaulXiCao 
292af0d731bSPaulXiCao     const auto is_sign_change = [tol](unsigned n, Real x) -> bool {
293af0d731bSPaulXiCao       return std::hermite(n, x - tol) * std::hermite(n, x + tol) < 0;
294af0d731bSPaulXiCao     };
295af0d731bSPaulXiCao 
296af0d731bSPaulXiCao     for (unsigned n = 0; n <= 20u; ++n) {
297af0d731bSPaulXiCao       for (Real x : get_roots<Real>(n)) {
298af0d731bSPaulXiCao         // the roots are symmetric: if x is a root, so is -x
299af0d731bSPaulXiCao         if (x > 0)
300af0d731bSPaulXiCao           assert(is_sign_change(n, -x));
301af0d731bSPaulXiCao         assert(is_sign_change(n, x));
302af0d731bSPaulXiCao       }
303af0d731bSPaulXiCao     }
304af0d731bSPaulXiCao   }
305af0d731bSPaulXiCao 
306*f343fee8SZibi Sarbinowski   if constexpr (std::numeric_limits<Real>::has_infinity) { // check input infinity is handled correctly
307af0d731bSPaulXiCao     Real inf = std::numeric_limits<Real>::infinity();
308*f343fee8SZibi Sarbinowski     for (unsigned n = 1; n < get_maximal_order<Real>(); ++n) {
309af0d731bSPaulXiCao       assert(std::hermite(n, +inf) == inf);
310af0d731bSPaulXiCao       assert(std::hermite(n, -inf) == ((n & 1) ? -inf : inf));
311af0d731bSPaulXiCao     }
312af0d731bSPaulXiCao   }
313af0d731bSPaulXiCao 
314*f343fee8SZibi Sarbinowski   if constexpr (std::numeric_limits<
315*f343fee8SZibi Sarbinowski                     Real>::has_infinity) { // check: if overflow occurs that it is mapped to the correct infinity
316af0d731bSPaulXiCao     if constexpr (std::is_same_v<Real, double>) {
317af0d731bSPaulXiCao       // Q: Why only double?
318af0d731bSPaulXiCao       // A: The numeric values (e.g. overflow threshold `n`) below are different for other types.
319af0d731bSPaulXiCao       static_assert(sizeof(double) == 8);
320*f343fee8SZibi Sarbinowski       for (unsigned n = 0; n < get_maximal_order<Real>(); ++n) {
321af0d731bSPaulXiCao         // Q: Why n=111 and x=300?
322*f343fee8SZibi Sarbinowski         // A: Both are chosen s.t. the first overlow occurs for some `n<get_maximal_order<Real>()`.
323af0d731bSPaulXiCao         if (n < 111) {
324af0d731bSPaulXiCao           assert(std::isfinite(std::hermite(n, +300.0)));
325af0d731bSPaulXiCao           assert(std::isfinite(std::hermite(n, -300.0)));
326af0d731bSPaulXiCao         } else {
327af0d731bSPaulXiCao           double inf = std::numeric_limits<double>::infinity();
328af0d731bSPaulXiCao           assert(std::hermite(n, +300.0) == inf);
329af0d731bSPaulXiCao           assert(std::hermite(n, -300.0) == ((n & 1) ? -inf : inf));
330af0d731bSPaulXiCao         }
331af0d731bSPaulXiCao       }
332af0d731bSPaulXiCao     }
333af0d731bSPaulXiCao   }
334af0d731bSPaulXiCao }
335af0d731bSPaulXiCao 
336af0d731bSPaulXiCao struct TestFloat {
337af0d731bSPaulXiCao   template <class Real>
338af0d731bSPaulXiCao   void operator()() {
339af0d731bSPaulXiCao     test<Real>();
340af0d731bSPaulXiCao   }
341af0d731bSPaulXiCao };
342af0d731bSPaulXiCao 
343af0d731bSPaulXiCao struct TestInt {
344af0d731bSPaulXiCao   template <class Integer>
345af0d731bSPaulXiCao   void operator()() {
346af0d731bSPaulXiCao     // checks that std::hermite(unsigned, Integer) actually wraps std::hermite(unsigned, double)
347*f343fee8SZibi Sarbinowski     for (unsigned n = 0; n < get_maximal_order<double>(); ++n)
348af0d731bSPaulXiCao       for (Integer x : {-42, -7, -5, -1, 0, 1, 5, 7, 42})
349af0d731bSPaulXiCao         assert(std::hermite(n, x) == std::hermite(n, static_cast<double>(x)));
350af0d731bSPaulXiCao   }
351af0d731bSPaulXiCao };
352af0d731bSPaulXiCao 
353af0d731bSPaulXiCao int main() {
354af0d731bSPaulXiCao   types::for_each(types::floating_point_types(), TestFloat());
355af0d731bSPaulXiCao   types::for_each(types::type_list<short, int, long, long long>(), TestInt());
356af0d731bSPaulXiCao }
357