26
26
27
27
#include " type_algorithms.h"
28
28
29
- inline constexpr unsigned g_max_n =
30
- #if !(defined(__MVS__) && !defined(__BFP__))
31
- 128 ;
32
- #else
33
- 39 ;
34
- #endif
29
+ template <class Real >
30
+ constexpr unsigned get_maximal_order () {
31
+ if constexpr (std::numeric_limits<Real>::max_exponent10 < std::numeric_limits<Real>::max_exponent)
32
+ return 128 ;
33
+ else
34
+ return 39 ;
35
+ }
35
36
36
37
template <class T >
37
38
std::array<T, 11 > sample_points () {
@@ -208,20 +209,23 @@ std::vector<T> get_roots(unsigned n) {
208
209
209
210
template <class Real >
210
211
void test () {
211
- #if !(defined(__MVS__) && !defined(__BFP__))
212
- { // checks if NaNs are reported correctly (i.e. output == input for input == NaN)
212
+ if constexpr (
213
+ std::numeric_limits<Real>::has_quiet_NaN &&
214
+ std::numeric_limits<
215
+ Real>::has_signaling_NaN) { // checks if NaNs are reported correctly (i.e. output == input for input == NaN)
213
216
using nl = std::numeric_limits<Real>;
214
217
for (Real NaN : {nl::quiet_NaN (), nl::signaling_NaN ()})
215
- for (unsigned n = 0 ; n < g_max_n ; ++n)
218
+ for (unsigned n = 0 ; n < get_maximal_order<Real>() ; ++n)
216
219
assert (std::isnan (std::hermite (n, NaN)));
217
220
}
218
221
219
- { // simple sample points for n=0..127 should not produce NaNs.
222
+ if constexpr (std::numeric_limits<Real>::has_quiet_NaN &&
223
+ std::numeric_limits<
224
+ Real>::has_signaling_NaN) { // simple sample points for n=0..127 should not produce NaNs.
220
225
for (Real x : sample_points<Real>())
221
- for (unsigned n = 0 ; n < g_max_n ; ++n)
226
+ for (unsigned n = 0 ; n < get_maximal_order<Real>() ; ++n)
222
227
assert (!std::isnan (std::hermite (n, x)));
223
228
}
224
- #endif
225
229
226
230
{ // checks std::hermite(n, x) for n=0..5 against analytic polynoms
227
231
const auto h0 = [](Real) -> Real { return 1 ; };
@@ -244,21 +248,21 @@ void test() {
244
248
245
249
{ // checks std::hermitef for bitwise equality with std::hermite(unsigned, float)
246
250
if constexpr (std::is_same_v<Real, float >)
247
- for (unsigned n = 0 ; n < g_max_n ; ++n)
251
+ for (unsigned n = 0 ; n < get_maximal_order<Real>() ; ++n)
248
252
for (float x : sample_points<float >())
249
253
assert (std::hermite (n, x) == std::hermitef (n, x));
250
254
}
251
255
252
256
{ // checks std::hermitel for bitwise equality with std::hermite(unsigned, long double)
253
257
if constexpr (std::is_same_v<Real, long double >)
254
- for (unsigned n = 0 ; n < g_max_n ; ++n)
258
+ for (unsigned n = 0 ; n < get_maximal_order<Real>() ; ++n)
255
259
for (long double x : sample_points<long double >())
256
260
assert (std::hermite (n, x) == std::hermitel (n, x));
257
261
}
258
262
259
263
{ // Checks if the characteristic recurrence relation holds: H_{n+1}(x) = 2x H_n(x) - 2n H_{n-1}(x)
260
264
for (Real x : sample_points<Real>()) {
261
- for (unsigned n = 1 ; n < g_max_n - 1 ; ++n) {
265
+ for (unsigned n = 1 ; n < get_maximal_order<Real>() - 1 ; ++n) {
262
266
Real H_next = std::hermite (n + 1 , x);
263
267
Real H_next_recurrence = 2 * (x * std::hermite (n, x) - n * std::hermite (n - 1 , x));
264
268
@@ -296,23 +300,23 @@ void test() {
296
300
}
297
301
}
298
302
299
- #if !(defined(__MVS__) && !defined(__BFP__))
300
- { // check input infinity is handled correctly
303
+ if constexpr (std::numeric_limits<Real>::has_infinity) { // check input infinity is handled correctly
301
304
Real inf = std::numeric_limits<Real>::infinity ();
302
- for (unsigned n = 1 ; n < g_max_n ; ++n) {
305
+ for (unsigned n = 1 ; n < get_maximal_order<Real>() ; ++n) {
303
306
assert (std::hermite (n, +inf) == inf);
304
307
assert (std::hermite (n, -inf) == ((n & 1 ) ? -inf : inf));
305
308
}
306
309
}
307
310
308
- { // check: if overflow occurs that it is mapped to the correct infinity
311
+ if constexpr (std::numeric_limits<
312
+ Real>::has_infinity) { // check: if overflow occurs that it is mapped to the correct infinity
309
313
if constexpr (std::is_same_v<Real, double >) {
310
314
// Q: Why only double?
311
315
// A: The numeric values (e.g. overflow threshold `n`) below are different for other types.
312
316
static_assert (sizeof (double ) == 8 );
313
- for (unsigned n = 0 ; n < g_max_n ; ++n) {
317
+ for (unsigned n = 0 ; n < get_maximal_order<Real>() ; ++n) {
314
318
// Q: Why n=111 and x=300?
315
- // A: Both are chosen s.t. the first overlow occurs for some `n<g_max_n `.
319
+ // A: Both are chosen s.t. the first overlow occurs for some `n<get_maximal_order<Real>() `.
316
320
if (n < 111 ) {
317
321
assert (std::isfinite (std::hermite (n, +300.0 )));
318
322
assert (std::isfinite (std::hermite (n, -300.0 )));
@@ -324,7 +328,6 @@ void test() {
324
328
}
325
329
}
326
330
}
327
- #endif
328
331
}
329
332
330
333
struct TestFloat {
@@ -338,7 +341,7 @@ struct TestInt {
338
341
template <class Integer >
339
342
void operator ()() {
340
343
// checks that std::hermite(unsigned, Integer) actually wraps std::hermite(unsigned, double)
341
- for (unsigned n = 0 ; n < g_max_n ; ++n)
344
+ for (unsigned n = 0 ; n < get_maximal_order< double >() ; ++n)
342
345
for (Integer x : {-42 , -7 , -5 , -1 , 0 , 1 , 5 , 7 , 42 })
343
346
assert (std::hermite (n, x) == std::hermite (n, static_cast <double >(x)));
344
347
}
0 commit comments