1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14
13 // double hermite(unsigned n, double x);
14 // float hermite(unsigned n, float x);
15 // long double hermite(unsigned n, long double x);
16 // float hermitef(unsigned n, float x);
17 // long double hermitel(unsigned n, long double x);
18 // template <class Integer>
19 // double hermite(unsigned n, Integer x);
27 #include "type_algorithms.h"
30 constexpr unsigned get_maximal_order() {
31 if constexpr (std::numeric_limits
<Real
>::is_iec559
)
33 else { // Workaround for z/OS HexFloat.
34 // Note |H_n(x)| < 10^75 for n < 39 and x in sample_points().
35 static_assert(std::numeric_limits
<Real
>::max_exponent10
== 75);
41 std::array
<T
, 11> sample_points() {
42 return {-12.34, -7.42, -1.0, -0.5, -0.1, 0.0, 0.1, 0.5, 1.0, 5.67, 15.67};
46 class CompareFloatingValues
{
52 CompareFloatingValues() {
53 abs_tol
= []() -> Real
{
54 if (std::is_same_v
<Real
, float>)
56 else if (std::is_same_v
<Real
, double>)
65 bool operator()(Real result
, Real expected
) const {
66 if (std::isinf(expected
) && std::isinf(result
))
67 return result
== expected
;
69 if (std::isnan(expected
) || std::isnan(result
))
72 Real tol
= abs_tol
+ std::abs(expected
) * rel_tol
;
73 return std::abs(result
- expected
) < tol
;
77 // Roots are taken from
78 // Salzer, Herbert E., Ruth Zucker, and Ruth Capuano.
79 // Table of the zeros and weight factors of the first twenty Hermite
80 // polynomials. US Government Printing Office, 1952.
82 std::vector
<T
> get_roots(unsigned n
) {
89 return {T(0.707106781186548)};
91 return {T(0), T(1.224744871391589)};
93 return {T(0.524647623275290), T(1.650680123885785)};
95 return {T(0), T(0.958572464613819), T(2.020182870456086)};
97 return {T(0.436077411927617), T(1.335849074013697), T(2.350604973674492)};
99 return {T(0), T(0.816287882858965), T(1.673551628767471), T(2.651961356835233)};
101 return {T(0.381186990207322), T(1.157193712446780), T(1.981656756695843), T(2.930637420257244)};
103 return {T(0), T(0.723551018752838), T(1.468553289216668), T(2.266580584531843), T(3.190993201781528)};
106 T(0.342901327223705), T(1.036610829789514), T(1.756683649299882), T(2.532731674232790), T(3.436159118837738)};
110 T(1.326557084494933),
111 T(2.025948015825755),
112 T(2.783290099781652),
113 T(3.668470846559583)};
116 return {T(0.314240376254359),
117 T(0.947788391240164),
118 T(1.597682635152605),
119 T(2.279507080501060),
120 T(3.020637025120890),
121 T(3.889724897869782)};
125 T(0.605763879171060),
126 T(1.220055036590748),
127 T(1.853107651601512),
128 T(2.519735685678238),
129 T(3.246608978372410),
130 T(4.101337596178640)};
133 return {T(0.29174551067256),
139 T(4.30444857047363)};
142 return {T(0.00000000000000),
149 T(4.49999070730939)};
152 return {T(0.27348104613815),
159 T(4.68873893930582)};
173 return {T(0.2582677505191),
196 return {T(0.2453407083009),
207 default: // polynom degree n>20 is unsupported
213 template <class Real
>
216 std::numeric_limits
<Real
>::has_quiet_NaN
&&
218 Real
>::has_signaling_NaN
) { // checks if NaNs are reported correctly (i.e. output == input for input == NaN)
219 using nl
= std::numeric_limits
<Real
>;
220 for (Real NaN
: {nl::quiet_NaN(), nl::signaling_NaN()})
221 for (unsigned n
= 0; n
< get_maximal_order
<Real
>(); ++n
)
222 assert(std::isnan(std::hermite(n
, NaN
)));
225 if constexpr (std::numeric_limits
<Real
>::has_quiet_NaN
&&
227 Real
>::has_signaling_NaN
) { // simple sample points for n=0..127 should not produce NaNs.
228 for (Real x
: sample_points
<Real
>())
229 for (unsigned n
= 0; n
< get_maximal_order
<Real
>(); ++n
)
230 assert(!std::isnan(std::hermite(n
, x
)));
233 { // checks std::hermite(n, x) for n=0..5 against analytic polynoms
234 const auto h0
= [](Real
) -> Real
{ return 1; };
235 const auto h1
= [](Real y
) -> Real
{ return 2 * y
; };
236 const auto h2
= [](Real y
) -> Real
{ return 4 * y
* y
- 2; };
237 const auto h3
= [](Real y
) -> Real
{ return y
* (8 * y
* y
- 12); };
238 const auto h4
= [](Real y
) -> Real
{ return (16 * std::pow(y
, 4) - 48 * y
* y
+ 12); };
239 const auto h5
= [](Real y
) -> Real
{ return y
* (32 * std::pow(y
, 4) - 160 * y
* y
+ 120); };
241 for (Real x
: sample_points
<Real
>()) {
242 const CompareFloatingValues
<Real
> compare
;
243 assert(compare(std::hermite(0, x
), h0(x
)));
244 assert(compare(std::hermite(1, x
), h1(x
)));
245 assert(compare(std::hermite(2, x
), h2(x
)));
246 assert(compare(std::hermite(3, x
), h3(x
)));
247 assert(compare(std::hermite(4, x
), h4(x
)));
248 assert(compare(std::hermite(5, x
), h5(x
)));
252 { // checks std::hermitef for bitwise equality with std::hermite(unsigned, float)
253 if constexpr (std::is_same_v
<Real
, float>)
254 for (unsigned n
= 0; n
< get_maximal_order
<Real
>(); ++n
)
255 for (float x
: sample_points
<float>())
256 assert(std::hermite(n
, x
) == std::hermitef(n
, x
));
259 { // checks std::hermitel for bitwise equality with std::hermite(unsigned, long double)
260 if constexpr (std::is_same_v
<Real
, long double>)
261 for (unsigned n
= 0; n
< get_maximal_order
<Real
>(); ++n
)
262 for (long double x
: sample_points
<long double>())
263 assert(std::hermite(n
, x
) == std::hermitel(n
, x
));
266 { // Checks if the characteristic recurrence relation holds: H_{n+1}(x) = 2x H_n(x) - 2n H_{n-1}(x)
267 for (Real x
: sample_points
<Real
>()) {
268 for (unsigned n
= 1; n
< get_maximal_order
<Real
>() - 1; ++n
) {
269 Real H_next
= std::hermite(n
+ 1, x
);
270 Real H_next_recurrence
= 2 * (x
* std::hermite(n
, x
) - n
* std::hermite(n
- 1, x
));
272 if (std::isinf(H_next
))
274 const CompareFloatingValues
<Real
> compare
;
275 assert(compare(H_next
, H_next_recurrence
));
280 { // sanity checks: hermite polynoms need to change signs at (simple) roots. checked upto order n<=20.
282 // root tolerance: must be smaller than the smallest difference between adjacent roots
283 Real tol
= []() -> Real
{
284 if (std::is_same_v
<Real
, float>)
286 else if (std::is_same_v
<Real
, double>)
292 const auto is_sign_change
= [tol
](unsigned n
, Real x
) -> bool {
293 return std::hermite(n
, x
- tol
) * std::hermite(n
, x
+ tol
) < 0;
296 for (unsigned n
= 0; n
<= 20u; ++n
) {
297 for (Real x
: get_roots
<Real
>(n
)) {
298 // the roots are symmetric: if x is a root, so is -x
300 assert(is_sign_change(n
, -x
));
301 assert(is_sign_change(n
, x
));
306 if constexpr (std::numeric_limits
<Real
>::has_infinity
) { // check input infinity is handled correctly
307 Real inf
= std::numeric_limits
<Real
>::infinity();
308 for (unsigned n
= 1; n
< get_maximal_order
<Real
>(); ++n
) {
309 assert(std::hermite(n
, +inf
) == inf
);
310 assert(std::hermite(n
, -inf
) == ((n
& 1) ? -inf
: inf
));
314 if constexpr (std::numeric_limits
<
315 Real
>::has_infinity
) { // check: if overflow occurs that it is mapped to the correct infinity
316 if constexpr (std::is_same_v
<Real
, double>) {
317 // Q: Why only double?
318 // A: The numeric values (e.g. overflow threshold `n`) below are different for other types.
319 static_assert(sizeof(double) == 8);
320 for (unsigned n
= 0; n
< get_maximal_order
<Real
>(); ++n
) {
321 // Q: Why n=111 and x=300?
322 // A: Both are chosen s.t. the first overlow occurs for some `n<get_maximal_order<Real>()`.
324 assert(std::isfinite(std::hermite(n
, +300.0)));
325 assert(std::isfinite(std::hermite(n
, -300.0)));
327 double inf
= std::numeric_limits
<double>::infinity();
328 assert(std::hermite(n
, +300.0) == inf
);
329 assert(std::hermite(n
, -300.0) == ((n
& 1) ? -inf
: inf
));
337 template <class Real
>
344 template <class Integer
>
346 // checks that std::hermite(unsigned, Integer) actually wraps std::hermite(unsigned, double)
347 for (unsigned n
= 0; n
< get_maximal_order
<double>(); ++n
)
348 for (Integer x
: {-42, -7, -5, -1, 0, 1, 5, 7, 42})
349 assert(std::hermite(n
, x
) == std::hermite(n
, static_cast<double>(x
)));
354 types::for_each(types::floating_point_types(), TestFloat());
355 types::for_each(types::type_list
<short, int, long, long long>(), TestInt());