26
26
27
27
#include " type_algorithms.h"
28
28
29
- inline constexpr unsigned g_max_n = 128 ;
29
+ template <class Real >
30
+ constexpr unsigned get_maximal_order () {
31
+ if constexpr (std::numeric_limits<Real>::is_iec559)
32
+ return 128 ;
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 );
36
+ return 39 ;
37
+ }
38
+ }
30
39
31
40
template <class T >
32
41
std::array<T, 11 > sample_points () {
@@ -203,16 +212,21 @@ std::vector<T> get_roots(unsigned n) {
203
212
204
213
template <class Real >
205
214
void test () {
206
- { // checks if NaNs are reported correctly (i.e. output == input for input == NaN)
215
+ if constexpr (
216
+ std::numeric_limits<Real>::has_quiet_NaN &&
217
+ std::numeric_limits<
218
+ Real>::has_signaling_NaN) { // checks if NaNs are reported correctly (i.e. output == input for input == NaN)
207
219
using nl = std::numeric_limits<Real>;
208
220
for (Real NaN : {nl::quiet_NaN (), nl::signaling_NaN ()})
209
- for (unsigned n = 0 ; n < g_max_n ; ++n)
221
+ for (unsigned n = 0 ; n < get_maximal_order<Real>() ; ++n)
210
222
assert (std::isnan (std::hermite (n, NaN)));
211
223
}
212
224
213
- { // simple sample points for n=0..127 should not produce NaNs.
225
+ if constexpr (std::numeric_limits<Real>::has_quiet_NaN &&
226
+ std::numeric_limits<
227
+ Real>::has_signaling_NaN) { // simple sample points for n=0..127 should not produce NaNs.
214
228
for (Real x : sample_points<Real>())
215
- for (unsigned n = 0 ; n < g_max_n ; ++n)
229
+ for (unsigned n = 0 ; n < get_maximal_order<Real>() ; ++n)
216
230
assert (!std::isnan (std::hermite (n, x)));
217
231
}
218
232
@@ -237,21 +251,21 @@ void test() {
237
251
238
252
{ // checks std::hermitef for bitwise equality with std::hermite(unsigned, float)
239
253
if constexpr (std::is_same_v<Real, float >)
240
- for (unsigned n = 0 ; n < g_max_n ; ++n)
254
+ for (unsigned n = 0 ; n < get_maximal_order<Real>() ; ++n)
241
255
for (float x : sample_points<float >())
242
256
assert (std::hermite (n, x) == std::hermitef (n, x));
243
257
}
244
258
245
259
{ // checks std::hermitel for bitwise equality with std::hermite(unsigned, long double)
246
260
if constexpr (std::is_same_v<Real, long double >)
247
- for (unsigned n = 0 ; n < g_max_n ; ++n)
261
+ for (unsigned n = 0 ; n < get_maximal_order<Real>() ; ++n)
248
262
for (long double x : sample_points<long double >())
249
263
assert (std::hermite (n, x) == std::hermitel (n, x));
250
264
}
251
265
252
266
{ // Checks if the characteristic recurrence relation holds: H_{n+1}(x) = 2x H_n(x) - 2n H_{n-1}(x)
253
267
for (Real x : sample_points<Real>()) {
254
- for (unsigned n = 1 ; n < g_max_n - 1 ; ++n) {
268
+ for (unsigned n = 1 ; n < get_maximal_order<Real>() - 1 ; ++n) {
255
269
Real H_next = std::hermite (n + 1 , x);
256
270
Real H_next_recurrence = 2 * (x * std::hermite (n, x) - n * std::hermite (n - 1 , x));
257
271
@@ -289,22 +303,23 @@ void test() {
289
303
}
290
304
}
291
305
292
- { // check input infinity is handled correctly
306
+ if constexpr (std::numeric_limits<Real>::has_infinity) { // check input infinity is handled correctly
293
307
Real inf = std::numeric_limits<Real>::infinity ();
294
- for (unsigned n = 1 ; n < g_max_n ; ++n) {
308
+ for (unsigned n = 1 ; n < get_maximal_order<Real>() ; ++n) {
295
309
assert (std::hermite (n, +inf) == inf);
296
310
assert (std::hermite (n, -inf) == ((n & 1 ) ? -inf : inf));
297
311
}
298
312
}
299
313
300
- { // check: if overflow occurs that it is mapped to the correct infinity
314
+ if constexpr (std::numeric_limits<
315
+ Real>::has_infinity) { // check: if overflow occurs that it is mapped to the correct infinity
301
316
if constexpr (std::is_same_v<Real, double >) {
302
317
// Q: Why only double?
303
318
// A: The numeric values (e.g. overflow threshold `n`) below are different for other types.
304
319
static_assert (sizeof (double ) == 8 );
305
- for (unsigned n = 0 ; n < g_max_n ; ++n) {
320
+ for (unsigned n = 0 ; n < get_maximal_order<Real>() ; ++n) {
306
321
// Q: Why n=111 and x=300?
307
- // A: Both are chosen s.t. the first overlow occurs for some `n<g_max_n `.
322
+ // A: Both are chosen s.t. the first overlow occurs for some `n<get_maximal_order<Real>() `.
308
323
if (n < 111 ) {
309
324
assert (std::isfinite (std::hermite (n, +300.0 )));
310
325
assert (std::isfinite (std::hermite (n, -300.0 )));
@@ -329,7 +344,7 @@ struct TestInt {
329
344
template <class Integer >
330
345
void operator ()() {
331
346
// checks that std::hermite(unsigned, Integer) actually wraps std::hermite(unsigned, double)
332
- for (unsigned n = 0 ; n < g_max_n ; ++n)
347
+ for (unsigned n = 0 ; n < get_maximal_order< double >() ; ++n)
333
348
for (Integer x : {-42 , -7 , -5 , -1 , 0 , 1 , 5 , 7 , 42 })
334
349
assert (std::hermite (n, x) == std::hermite (n, static_cast <double >(x)));
335
350
}
0 commit comments