1 //===-- runtime/numeric.cpp -----------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "flang/Runtime/numeric.h"
10 #include "terminator.h"
11 #include "flang/Runtime/float128.h"
12 #include <cfloat>
13 #include <climits>
14 #include <cmath>
15 #include <limits>
16 
17 namespace Fortran::runtime {
18 
19 template <typename RES>
20 inline RES getIntArgValue(const char *source, int line, void *arg, int kind,
21     std::int64_t defaultValue, int resKind) {
22   RES res;
23   if (!arg) {
24     res = static_cast<RES>(defaultValue);
25   } else if (kind == 1) {
26     res = static_cast<RES>(
27         *static_cast<CppTypeFor<TypeCategory::Integer, 1> *>(arg));
28   } else if (kind == 2) {
29     res = static_cast<RES>(
30         *static_cast<CppTypeFor<TypeCategory::Integer, 2> *>(arg));
31   } else if (kind == 4) {
32     res = static_cast<RES>(
33         *static_cast<CppTypeFor<TypeCategory::Integer, 4> *>(arg));
34   } else if (kind == 8) {
35     res = static_cast<RES>(
36         *static_cast<CppTypeFor<TypeCategory::Integer, 8> *>(arg));
37 #ifdef __SIZEOF_INT128__
38   } else if (kind == 16) {
39     if (resKind != 16) {
40       Terminator{source, line}.Crash("Unexpected integer kind in runtime");
41     }
42     res = static_cast<RES>(
43         *static_cast<CppTypeFor<TypeCategory::Integer, 16> *>(arg));
44 #endif
45   } else {
46     Terminator{source, line}.Crash("Unexpected integer kind in runtime");
47   }
48   return res;
49 }
50 
51 // NINT (16.9.141)
52 template <typename RESULT, typename ARG> inline RESULT Nint(ARG x) {
53   if (x >= 0) {
54     return std::trunc(x + ARG{0.5});
55   } else {
56     return std::trunc(x - ARG{0.5});
57   }
58 }
59 
60 // CEILING & FLOOR (16.9.43, .79)
61 template <typename RESULT, typename ARG> inline RESULT Ceiling(ARG x) {
62   return std::ceil(x);
63 }
64 template <typename RESULT, typename ARG> inline RESULT Floor(ARG x) {
65   return std::floor(x);
66 }
67 
68 // EXPONENT (16.9.75)
69 template <typename RESULT, typename ARG> inline RESULT Exponent(ARG x) {
70   if (std::isinf(x) || std::isnan(x)) {
71     return std::numeric_limits<RESULT>::max(); // +/-Inf, NaN -> HUGE(0)
72   } else if (x == 0) {
73     return 0; // 0 -> 0
74   } else {
75     return std::ilogb(x) + 1;
76   }
77 }
78 
79 // FRACTION (16.9.80)
80 template <typename T> inline T Fraction(T x) {
81   if (std::isnan(x)) {
82     return x; // NaN -> same NaN
83   } else if (std::isinf(x)) {
84     return std::numeric_limits<T>::quiet_NaN(); // +/-Inf -> NaN
85   } else if (x == 0) {
86     return 0; // 0 -> 0
87   } else {
88     int ignoredExp;
89     return std::frexp(x, &ignoredExp);
90   }
91 }
92 
93 // MOD & MODULO (16.9.135, .136)
94 template <bool IS_MODULO, typename T>
95 inline T IntMod(T x, T p, const char *sourceFile, int sourceLine) {
96   if (p == 0) {
97     Terminator{sourceFile, sourceLine}.Crash(
98         IS_MODULO ? "MODULO with P==0" : "MOD with P==0");
99   }
100   auto mod{x - (x / p) * p};
101   if (IS_MODULO && (x > 0) != (p > 0)) {
102     mod += p;
103   }
104   return mod;
105 }
106 template <bool IS_MODULO, typename T>
107 inline T RealMod(T a, T p, const char *sourceFile, int sourceLine) {
108   if (p == 0) {
109     Terminator{sourceFile, sourceLine}.Crash(
110         IS_MODULO ? "MODULO with P==0" : "MOD with P==0");
111   }
112   T quotient{a / p};
113   if (std::isinf(quotient) && std::isfinite(a) && std::isfinite(p)) {
114     // a/p overflowed -- so it must be an integer, and the result
115     // must be a zero of the same sign as one of the operands.
116     return std::copysign(T{}, IS_MODULO ? p : a);
117   }
118   T toInt{IS_MODULO ? std::floor(quotient) : std::trunc(quotient)};
119   return a - toInt * p;
120 }
121 
122 // RRSPACING (16.9.164)
123 template <int PREC, typename T> inline T RRSpacing(T x) {
124   if (std::isnan(x)) {
125     return x; // NaN -> same NaN
126   } else if (std::isinf(x)) {
127     return std::numeric_limits<T>::quiet_NaN(); // +/-Inf -> NaN
128   } else if (x == 0) {
129     return 0; // 0 -> 0
130   } else {
131     return std::ldexp(std::abs(x), PREC - (std::ilogb(x) + 1));
132   }
133 }
134 
135 // SCALE (16.9.166)
136 template <typename T> inline T Scale(T x, std::int64_t p) {
137   auto ip{static_cast<int>(p)};
138   if (ip != p) {
139     ip = p < 0 ? std::numeric_limits<int>::min()
140                : std::numeric_limits<int>::max();
141   }
142   return std::ldexp(x, p); // x*2**p
143 }
144 
145 // SELECTED_INT_KIND (16.9.169)
146 template <typename T>
147 inline CppTypeFor<TypeCategory::Integer, 4> SelectedIntKind(T x) {
148   if (x <= 2) {
149     return 1;
150   } else if (x <= 4) {
151     return 2;
152   } else if (x <= 9) {
153     return 4;
154   } else if (x <= 18) {
155     return 8;
156 #ifdef __SIZEOF_INT128__
157   } else if (x <= 38) {
158     return 16;
159 #endif
160   }
161   return -1;
162 }
163 
164 // SELECTED_REAL_KIND (16.9.170)
165 template <typename P, typename R, typename D>
166 inline CppTypeFor<TypeCategory::Integer, 4> SelectedRealKind(P p, R r, D d) {
167   if (d != 2) {
168     return -5;
169   }
170 
171   int error{0};
172   int kind{0};
173   if (p <= 3) {
174     kind = 2;
175   } else if (p <= 6) {
176     kind = 4;
177   } else if (p <= 15) {
178     kind = 8;
179 #if LDBL_MANT_DIG == 64
180   } else if (p <= 18) {
181     kind = 10;
182   } else if (p <= 33) {
183     kind = 16;
184 #elif LDBL_MANT_DIG == 113
185   } else if (p <= 33) {
186     kind = 16;
187 #endif
188   } else {
189     error -= 1;
190   }
191 
192   if (r <= 4) {
193     kind = kind < 2 ? 2 : kind;
194   } else if (r <= 37) {
195     kind = kind < 3 ? (p == 3 ? 4 : 3) : kind;
196   } else if (r <= 307) {
197     kind = kind < 8 ? 8 : kind;
198 #if LDBL_MANT_DIG == 64
199   } else if (r <= 4931) {
200     kind = kind < 10 ? 10 : kind;
201 #elif LDBL_MANT_DIG == 113
202   } else if (r <= 4931) {
203     kind = kind < 16 ? 16 : kind;
204 #endif
205   } else {
206     error -= 2;
207   }
208 
209   return error ? error : kind;
210 }
211 
212 // SET_EXPONENT (16.9.171)
213 template <typename T> inline T SetExponent(T x, std::int64_t p) {
214   if (std::isnan(x)) {
215     return x; // NaN -> same NaN
216   } else if (std::isinf(x)) {
217     return std::numeric_limits<T>::quiet_NaN(); // +/-Inf -> NaN
218   } else if (x == 0) {
219     return x; // return negative zero if x is negative zero
220   } else {
221     int expo{std::ilogb(x) + 1};
222     auto ip{static_cast<int>(p - expo)};
223     if (ip != p - expo) {
224       ip = p < 0 ? std::numeric_limits<int>::min()
225                  : std::numeric_limits<int>::max();
226     }
227     return std::ldexp(x, ip); // x*2**(p-e)
228   }
229 }
230 
231 // SPACING (16.9.180)
232 template <int PREC, typename T> inline T Spacing(T x) {
233   if (std::isnan(x)) {
234     return x; // NaN -> same NaN
235   } else if (std::isinf(x)) {
236     return std::numeric_limits<T>::quiet_NaN(); // +/-Inf -> NaN
237   } else if (x == 0) {
238     // The standard-mandated behavior seems broken, since TINY() can't be
239     // subnormal.
240     return std::numeric_limits<T>::min(); // 0 -> TINY(x)
241   } else {
242     return std::ldexp(
243         static_cast<T>(1.0), std::ilogb(x) + 1 - PREC); // 2**(e-p)
244   }
245 }
246 
247 // NEAREST (16.9.139)
248 template <int PREC, typename T> inline T Nearest(T x, bool positive) {
249   auto spacing{Spacing<PREC>(x)};
250   if (x == 0) {
251     auto least{std::numeric_limits<T>::denorm_min()};
252     return positive ? least : -least;
253   } else {
254     return positive ? x + spacing : x - spacing;
255   }
256 }
257 
258 extern "C" {
259 
260 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Ceiling4_1)(
261     CppTypeFor<TypeCategory::Real, 4> x) {
262   return Ceiling<CppTypeFor<TypeCategory::Integer, 1>>(x);
263 }
264 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Ceiling4_2)(
265     CppTypeFor<TypeCategory::Real, 4> x) {
266   return Ceiling<CppTypeFor<TypeCategory::Integer, 2>>(x);
267 }
268 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Ceiling4_4)(
269     CppTypeFor<TypeCategory::Real, 4> x) {
270   return Ceiling<CppTypeFor<TypeCategory::Integer, 4>>(x);
271 }
272 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Ceiling4_8)(
273     CppTypeFor<TypeCategory::Real, 4> x) {
274   return Ceiling<CppTypeFor<TypeCategory::Integer, 8>>(x);
275 }
276 #ifdef __SIZEOF_INT128__
277 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Ceiling4_16)(
278     CppTypeFor<TypeCategory::Real, 4> x) {
279   return Ceiling<CppTypeFor<TypeCategory::Integer, 16>>(x);
280 }
281 #endif
282 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Ceiling8_1)(
283     CppTypeFor<TypeCategory::Real, 8> x) {
284   return Ceiling<CppTypeFor<TypeCategory::Integer, 1>>(x);
285 }
286 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Ceiling8_2)(
287     CppTypeFor<TypeCategory::Real, 8> x) {
288   return Ceiling<CppTypeFor<TypeCategory::Integer, 2>>(x);
289 }
290 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Ceiling8_4)(
291     CppTypeFor<TypeCategory::Real, 8> x) {
292   return Ceiling<CppTypeFor<TypeCategory::Integer, 4>>(x);
293 }
294 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Ceiling8_8)(
295     CppTypeFor<TypeCategory::Real, 8> x) {
296   return Ceiling<CppTypeFor<TypeCategory::Integer, 8>>(x);
297 }
298 #ifdef __SIZEOF_INT128__
299 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Ceiling8_16)(
300     CppTypeFor<TypeCategory::Real, 8> x) {
301   return Ceiling<CppTypeFor<TypeCategory::Integer, 16>>(x);
302 }
303 #endif
304 #if LDBL_MANT_DIG == 64
305 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Ceiling10_1)(
306     CppTypeFor<TypeCategory::Real, 10> x) {
307   return Ceiling<CppTypeFor<TypeCategory::Integer, 1>>(x);
308 }
309 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Ceiling10_2)(
310     CppTypeFor<TypeCategory::Real, 10> x) {
311   return Ceiling<CppTypeFor<TypeCategory::Integer, 2>>(x);
312 }
313 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Ceiling10_4)(
314     CppTypeFor<TypeCategory::Real, 10> x) {
315   return Ceiling<CppTypeFor<TypeCategory::Integer, 4>>(x);
316 }
317 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Ceiling10_8)(
318     CppTypeFor<TypeCategory::Real, 10> x) {
319   return Ceiling<CppTypeFor<TypeCategory::Integer, 8>>(x);
320 }
321 #ifdef __SIZEOF_INT128__
322 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Ceiling10_16)(
323     CppTypeFor<TypeCategory::Real, 10> x) {
324   return Ceiling<CppTypeFor<TypeCategory::Integer, 16>>(x);
325 }
326 #endif
327 #elif LDBL_MANT_DIG == 113
328 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Ceiling16_1)(
329     CppTypeFor<TypeCategory::Real, 16> x) {
330   return Ceiling<CppTypeFor<TypeCategory::Integer, 1>>(x);
331 }
332 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Ceiling16_2)(
333     CppTypeFor<TypeCategory::Real, 16> x) {
334   return Ceiling<CppTypeFor<TypeCategory::Integer, 2>>(x);
335 }
336 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Ceiling16_4)(
337     CppTypeFor<TypeCategory::Real, 16> x) {
338   return Ceiling<CppTypeFor<TypeCategory::Integer, 4>>(x);
339 }
340 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Ceiling16_8)(
341     CppTypeFor<TypeCategory::Real, 16> x) {
342   return Ceiling<CppTypeFor<TypeCategory::Integer, 8>>(x);
343 }
344 #ifdef __SIZEOF_INT128__
345 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Ceiling16_16)(
346     CppTypeFor<TypeCategory::Real, 16> x) {
347   return Ceiling<CppTypeFor<TypeCategory::Integer, 16>>(x);
348 }
349 #endif
350 #endif
351 
352 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Exponent4_4)(
353     CppTypeFor<TypeCategory::Real, 4> x) {
354   return Exponent<CppTypeFor<TypeCategory::Integer, 4>>(x);
355 }
356 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Exponent4_8)(
357     CppTypeFor<TypeCategory::Real, 4> x) {
358   return Exponent<CppTypeFor<TypeCategory::Integer, 8>>(x);
359 }
360 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Exponent8_4)(
361     CppTypeFor<TypeCategory::Real, 8> x) {
362   return Exponent<CppTypeFor<TypeCategory::Integer, 4>>(x);
363 }
364 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Exponent8_8)(
365     CppTypeFor<TypeCategory::Real, 8> x) {
366   return Exponent<CppTypeFor<TypeCategory::Integer, 8>>(x);
367 }
368 #if LDBL_MANT_DIG == 64
369 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Exponent10_4)(
370     CppTypeFor<TypeCategory::Real, 10> x) {
371   return Exponent<CppTypeFor<TypeCategory::Integer, 4>>(x);
372 }
373 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Exponent10_8)(
374     CppTypeFor<TypeCategory::Real, 10> x) {
375   return Exponent<CppTypeFor<TypeCategory::Integer, 8>>(x);
376 }
377 #elif LDBL_MANT_DIG == 113
378 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Exponent16_4)(
379     CppTypeFor<TypeCategory::Real, 16> x) {
380   return Exponent<CppTypeFor<TypeCategory::Integer, 4>>(x);
381 }
382 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Exponent16_8)(
383     CppTypeFor<TypeCategory::Real, 16> x) {
384   return Exponent<CppTypeFor<TypeCategory::Integer, 8>>(x);
385 }
386 #endif
387 
388 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Floor4_1)(
389     CppTypeFor<TypeCategory::Real, 4> x) {
390   return Floor<CppTypeFor<TypeCategory::Integer, 1>>(x);
391 }
392 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Floor4_2)(
393     CppTypeFor<TypeCategory::Real, 4> x) {
394   return Floor<CppTypeFor<TypeCategory::Integer, 2>>(x);
395 }
396 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Floor4_4)(
397     CppTypeFor<TypeCategory::Real, 4> x) {
398   return Floor<CppTypeFor<TypeCategory::Integer, 4>>(x);
399 }
400 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Floor4_8)(
401     CppTypeFor<TypeCategory::Real, 4> x) {
402   return Floor<CppTypeFor<TypeCategory::Integer, 8>>(x);
403 }
404 #ifdef __SIZEOF_INT128__
405 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Floor4_16)(
406     CppTypeFor<TypeCategory::Real, 4> x) {
407   return Floor<CppTypeFor<TypeCategory::Integer, 16>>(x);
408 }
409 #endif
410 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Floor8_1)(
411     CppTypeFor<TypeCategory::Real, 8> x) {
412   return Floor<CppTypeFor<TypeCategory::Integer, 1>>(x);
413 }
414 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Floor8_2)(
415     CppTypeFor<TypeCategory::Real, 8> x) {
416   return Floor<CppTypeFor<TypeCategory::Integer, 2>>(x);
417 }
418 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Floor8_4)(
419     CppTypeFor<TypeCategory::Real, 8> x) {
420   return Floor<CppTypeFor<TypeCategory::Integer, 4>>(x);
421 }
422 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Floor8_8)(
423     CppTypeFor<TypeCategory::Real, 8> x) {
424   return Floor<CppTypeFor<TypeCategory::Integer, 8>>(x);
425 }
426 #ifdef __SIZEOF_INT128__
427 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Floor8_16)(
428     CppTypeFor<TypeCategory::Real, 8> x) {
429   return Floor<CppTypeFor<TypeCategory::Integer, 16>>(x);
430 }
431 #endif
432 #if LDBL_MANT_DIG == 64
433 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Floor10_1)(
434     CppTypeFor<TypeCategory::Real, 10> x) {
435   return Floor<CppTypeFor<TypeCategory::Integer, 1>>(x);
436 }
437 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Floor10_2)(
438     CppTypeFor<TypeCategory::Real, 10> x) {
439   return Floor<CppTypeFor<TypeCategory::Integer, 2>>(x);
440 }
441 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Floor10_4)(
442     CppTypeFor<TypeCategory::Real, 10> x) {
443   return Floor<CppTypeFor<TypeCategory::Integer, 4>>(x);
444 }
445 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Floor10_8)(
446     CppTypeFor<TypeCategory::Real, 10> x) {
447   return Floor<CppTypeFor<TypeCategory::Integer, 8>>(x);
448 }
449 #ifdef __SIZEOF_INT128__
450 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Floor10_16)(
451     CppTypeFor<TypeCategory::Real, 10> x) {
452   return Floor<CppTypeFor<TypeCategory::Integer, 16>>(x);
453 }
454 #endif
455 #elif LDBL_MANT_DIG == 113
456 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Floor16_1)(
457     CppTypeFor<TypeCategory::Real, 16> x) {
458   return Floor<CppTypeFor<TypeCategory::Integer, 1>>(x);
459 }
460 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Floor16_2)(
461     CppTypeFor<TypeCategory::Real, 16> x) {
462   return Floor<CppTypeFor<TypeCategory::Integer, 2>>(x);
463 }
464 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Floor16_4)(
465     CppTypeFor<TypeCategory::Real, 16> x) {
466   return Floor<CppTypeFor<TypeCategory::Integer, 4>>(x);
467 }
468 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Floor16_8)(
469     CppTypeFor<TypeCategory::Real, 16> x) {
470   return Floor<CppTypeFor<TypeCategory::Integer, 8>>(x);
471 }
472 #ifdef __SIZEOF_INT128__
473 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Floor16_16)(
474     CppTypeFor<TypeCategory::Real, 16> x) {
475   return Floor<CppTypeFor<TypeCategory::Integer, 16>>(x);
476 }
477 #endif
478 #endif
479 
480 CppTypeFor<TypeCategory::Real, 4> RTNAME(Fraction4)(
481     CppTypeFor<TypeCategory::Real, 4> x) {
482   return Fraction(x);
483 }
484 CppTypeFor<TypeCategory::Real, 8> RTNAME(Fraction8)(
485     CppTypeFor<TypeCategory::Real, 8> x) {
486   return Fraction(x);
487 }
488 #if LDBL_MANT_DIG == 64
489 CppTypeFor<TypeCategory::Real, 10> RTNAME(Fraction10)(
490     CppTypeFor<TypeCategory::Real, 10> x) {
491   return Fraction(x);
492 }
493 #elif LDBL_MANT_DIG == 113
494 CppTypeFor<TypeCategory::Real, 16> RTNAME(Fraction16)(
495     CppTypeFor<TypeCategory::Real, 16> x) {
496   return Fraction(x);
497 }
498 #endif
499 
500 bool RTNAME(IsFinite4)(CppTypeFor<TypeCategory::Real, 4> x) {
501   return std::isfinite(x);
502 }
503 bool RTNAME(IsFinite8)(CppTypeFor<TypeCategory::Real, 8> x) {
504   return std::isfinite(x);
505 }
506 #if LDBL_MANT_DIG == 64
507 bool RTNAME(IsFinite10)(CppTypeFor<TypeCategory::Real, 10> x) {
508   return std::isfinite(x);
509 }
510 #elif LDBL_MANT_DIG == 113
511 bool RTNAME(IsFinite16)(CppTypeFor<TypeCategory::Real, 16> x) {
512   return std::isfinite(x);
513 }
514 #endif
515 
516 bool RTNAME(IsNaN4)(CppTypeFor<TypeCategory::Real, 4> x) {
517   return std::isnan(x);
518 }
519 bool RTNAME(IsNaN8)(CppTypeFor<TypeCategory::Real, 8> x) {
520   return std::isnan(x);
521 }
522 #if LDBL_MANT_DIG == 64
523 bool RTNAME(IsNaN10)(CppTypeFor<TypeCategory::Real, 10> x) {
524   return std::isnan(x);
525 }
526 #elif LDBL_MANT_DIG == 113
527 bool RTNAME(IsNaN16)(CppTypeFor<TypeCategory::Real, 16> x) {
528   return std::isnan(x);
529 }
530 #endif
531 
532 CppTypeFor<TypeCategory::Integer, 1> RTNAME(ModInteger1)(
533     CppTypeFor<TypeCategory::Integer, 1> x,
534     CppTypeFor<TypeCategory::Integer, 1> p, const char *sourceFile,
535     int sourceLine) {
536   return IntMod<false>(x, p, sourceFile, sourceLine);
537 }
538 CppTypeFor<TypeCategory::Integer, 2> RTNAME(ModInteger2)(
539     CppTypeFor<TypeCategory::Integer, 2> x,
540     CppTypeFor<TypeCategory::Integer, 2> p, const char *sourceFile,
541     int sourceLine) {
542   return IntMod<false>(x, p, sourceFile, sourceLine);
543 }
544 CppTypeFor<TypeCategory::Integer, 4> RTNAME(ModInteger4)(
545     CppTypeFor<TypeCategory::Integer, 4> x,
546     CppTypeFor<TypeCategory::Integer, 4> p, const char *sourceFile,
547     int sourceLine) {
548   return IntMod<false>(x, p, sourceFile, sourceLine);
549 }
550 CppTypeFor<TypeCategory::Integer, 8> RTNAME(ModInteger8)(
551     CppTypeFor<TypeCategory::Integer, 8> x,
552     CppTypeFor<TypeCategory::Integer, 8> p, const char *sourceFile,
553     int sourceLine) {
554   return IntMod<false>(x, p, sourceFile, sourceLine);
555 }
556 #ifdef __SIZEOF_INT128__
557 CppTypeFor<TypeCategory::Integer, 16> RTNAME(ModInteger16)(
558     CppTypeFor<TypeCategory::Integer, 16> x,
559     CppTypeFor<TypeCategory::Integer, 16> p, const char *sourceFile,
560     int sourceLine) {
561   return IntMod<false>(x, p, sourceFile, sourceLine);
562 }
563 #endif
564 CppTypeFor<TypeCategory::Real, 4> RTNAME(ModReal4)(
565     CppTypeFor<TypeCategory::Real, 4> x, CppTypeFor<TypeCategory::Real, 4> p,
566     const char *sourceFile, int sourceLine) {
567   return RealMod<false>(x, p, sourceFile, sourceLine);
568 }
569 CppTypeFor<TypeCategory::Real, 8> RTNAME(ModReal8)(
570     CppTypeFor<TypeCategory::Real, 8> x, CppTypeFor<TypeCategory::Real, 8> p,
571     const char *sourceFile, int sourceLine) {
572   return RealMod<false>(x, p, sourceFile, sourceLine);
573 }
574 #if LDBL_MANT_DIG == 64
575 CppTypeFor<TypeCategory::Real, 10> RTNAME(ModReal10)(
576     CppTypeFor<TypeCategory::Real, 10> x, CppTypeFor<TypeCategory::Real, 10> p,
577     const char *sourceFile, int sourceLine) {
578   return RealMod<false>(x, p, sourceFile, sourceLine);
579 }
580 #elif LDBL_MANT_DIG == 113
581 CppTypeFor<TypeCategory::Real, 16> RTNAME(ModReal16)(
582     CppTypeFor<TypeCategory::Real, 16> x, CppTypeFor<TypeCategory::Real, 16> p,
583     const char *sourceFile, int sourceLine) {
584   return RealMod<false>(x, p, sourceFile, sourceLine);
585 }
586 #endif
587 
588 CppTypeFor<TypeCategory::Integer, 1> RTNAME(ModuloInteger1)(
589     CppTypeFor<TypeCategory::Integer, 1> x,
590     CppTypeFor<TypeCategory::Integer, 1> p, const char *sourceFile,
591     int sourceLine) {
592   return IntMod<true>(x, p, sourceFile, sourceLine);
593 }
594 CppTypeFor<TypeCategory::Integer, 2> RTNAME(ModuloInteger2)(
595     CppTypeFor<TypeCategory::Integer, 2> x,
596     CppTypeFor<TypeCategory::Integer, 2> p, const char *sourceFile,
597     int sourceLine) {
598   return IntMod<true>(x, p, sourceFile, sourceLine);
599 }
600 CppTypeFor<TypeCategory::Integer, 4> RTNAME(ModuloInteger4)(
601     CppTypeFor<TypeCategory::Integer, 4> x,
602     CppTypeFor<TypeCategory::Integer, 4> p, const char *sourceFile,
603     int sourceLine) {
604   return IntMod<true>(x, p, sourceFile, sourceLine);
605 }
606 CppTypeFor<TypeCategory::Integer, 8> RTNAME(ModuloInteger8)(
607     CppTypeFor<TypeCategory::Integer, 8> x,
608     CppTypeFor<TypeCategory::Integer, 8> p, const char *sourceFile,
609     int sourceLine) {
610   return IntMod<true>(x, p, sourceFile, sourceLine);
611 }
612 #ifdef __SIZEOF_INT128__
613 CppTypeFor<TypeCategory::Integer, 16> RTNAME(ModuloInteger16)(
614     CppTypeFor<TypeCategory::Integer, 16> x,
615     CppTypeFor<TypeCategory::Integer, 16> p, const char *sourceFile,
616     int sourceLine) {
617   return IntMod<true>(x, p, sourceFile, sourceLine);
618 }
619 #endif
620 CppTypeFor<TypeCategory::Real, 4> RTNAME(ModuloReal4)(
621     CppTypeFor<TypeCategory::Real, 4> x, CppTypeFor<TypeCategory::Real, 4> p,
622     const char *sourceFile, int sourceLine) {
623   return RealMod<true>(x, p, sourceFile, sourceLine);
624 }
625 CppTypeFor<TypeCategory::Real, 8> RTNAME(ModuloReal8)(
626     CppTypeFor<TypeCategory::Real, 8> x, CppTypeFor<TypeCategory::Real, 8> p,
627     const char *sourceFile, int sourceLine) {
628   return RealMod<true>(x, p, sourceFile, sourceLine);
629 }
630 #if LDBL_MANT_DIG == 64
631 CppTypeFor<TypeCategory::Real, 10> RTNAME(ModuloReal10)(
632     CppTypeFor<TypeCategory::Real, 10> x, CppTypeFor<TypeCategory::Real, 10> p,
633     const char *sourceFile, int sourceLine) {
634   return RealMod<true>(x, p, sourceFile, sourceLine);
635 }
636 #elif LDBL_MANT_DIG == 113
637 CppTypeFor<TypeCategory::Real, 16> RTNAME(ModuloReal16)(
638     CppTypeFor<TypeCategory::Real, 16> x, CppTypeFor<TypeCategory::Real, 16> p,
639     const char *sourceFile, int sourceLine) {
640   return RealMod<true>(x, p, sourceFile, sourceLine);
641 }
642 #endif
643 
644 CppTypeFor<TypeCategory::Real, 4> RTNAME(Nearest4)(
645     CppTypeFor<TypeCategory::Real, 4> x, bool positive) {
646   return Nearest<24>(x, positive);
647 }
648 CppTypeFor<TypeCategory::Real, 8> RTNAME(Nearest8)(
649     CppTypeFor<TypeCategory::Real, 8> x, bool positive) {
650   return Nearest<53>(x, positive);
651 }
652 #if LDBL_MANT_DIG == 64
653 CppTypeFor<TypeCategory::Real, 10> RTNAME(Nearest10)(
654     CppTypeFor<TypeCategory::Real, 10> x, bool positive) {
655   return Nearest<64>(x, positive);
656 }
657 #elif LDBL_MANT_DIG == 113
658 CppTypeFor<TypeCategory::Real, 16> RTNAME(Nearest16)(
659     CppTypeFor<TypeCategory::Real, 16> x, bool positive) {
660   return Nearest<113>(x, positive);
661 }
662 #endif
663 
664 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Nint4_1)(
665     CppTypeFor<TypeCategory::Real, 4> x) {
666   return Nint<CppTypeFor<TypeCategory::Integer, 1>>(x);
667 }
668 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Nint4_2)(
669     CppTypeFor<TypeCategory::Real, 4> x) {
670   return Nint<CppTypeFor<TypeCategory::Integer, 2>>(x);
671 }
672 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Nint4_4)(
673     CppTypeFor<TypeCategory::Real, 4> x) {
674   return Nint<CppTypeFor<TypeCategory::Integer, 4>>(x);
675 }
676 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Nint4_8)(
677     CppTypeFor<TypeCategory::Real, 4> x) {
678   return Nint<CppTypeFor<TypeCategory::Integer, 8>>(x);
679 }
680 #ifdef __SIZEOF_INT128__
681 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Nint4_16)(
682     CppTypeFor<TypeCategory::Real, 4> x) {
683   return Nint<CppTypeFor<TypeCategory::Integer, 16>>(x);
684 }
685 #endif
686 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Nint8_1)(
687     CppTypeFor<TypeCategory::Real, 8> x) {
688   return Nint<CppTypeFor<TypeCategory::Integer, 1>>(x);
689 }
690 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Nint8_2)(
691     CppTypeFor<TypeCategory::Real, 8> x) {
692   return Nint<CppTypeFor<TypeCategory::Integer, 2>>(x);
693 }
694 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Nint8_4)(
695     CppTypeFor<TypeCategory::Real, 8> x) {
696   return Nint<CppTypeFor<TypeCategory::Integer, 4>>(x);
697 }
698 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Nint8_8)(
699     CppTypeFor<TypeCategory::Real, 8> x) {
700   return Nint<CppTypeFor<TypeCategory::Integer, 8>>(x);
701 }
702 #ifdef __SIZEOF_INT128__
703 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Nint8_16)(
704     CppTypeFor<TypeCategory::Real, 8> x) {
705   return Nint<CppTypeFor<TypeCategory::Integer, 16>>(x);
706 }
707 #endif
708 #if LDBL_MANT_DIG == 64
709 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Nint10_1)(
710     CppTypeFor<TypeCategory::Real, 10> x) {
711   return Nint<CppTypeFor<TypeCategory::Integer, 1>>(x);
712 }
713 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Nint10_2)(
714     CppTypeFor<TypeCategory::Real, 10> x) {
715   return Nint<CppTypeFor<TypeCategory::Integer, 2>>(x);
716 }
717 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Nint10_4)(
718     CppTypeFor<TypeCategory::Real, 10> x) {
719   return Nint<CppTypeFor<TypeCategory::Integer, 4>>(x);
720 }
721 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Nint10_8)(
722     CppTypeFor<TypeCategory::Real, 10> x) {
723   return Nint<CppTypeFor<TypeCategory::Integer, 8>>(x);
724 }
725 #ifdef __SIZEOF_INT128__
726 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Nint10_16)(
727     CppTypeFor<TypeCategory::Real, 10> x) {
728   return Nint<CppTypeFor<TypeCategory::Integer, 16>>(x);
729 }
730 #endif
731 #elif LDBL_MANT_DIG == 113
732 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Nint16_1)(
733     CppTypeFor<TypeCategory::Real, 16> x) {
734   return Nint<CppTypeFor<TypeCategory::Integer, 1>>(x);
735 }
736 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Nint16_2)(
737     CppTypeFor<TypeCategory::Real, 16> x) {
738   return Nint<CppTypeFor<TypeCategory::Integer, 2>>(x);
739 }
740 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Nint16_4)(
741     CppTypeFor<TypeCategory::Real, 16> x) {
742   return Nint<CppTypeFor<TypeCategory::Integer, 4>>(x);
743 }
744 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Nint16_8)(
745     CppTypeFor<TypeCategory::Real, 16> x) {
746   return Nint<CppTypeFor<TypeCategory::Integer, 8>>(x);
747 }
748 #ifdef __SIZEOF_INT128__
749 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Nint16_16)(
750     CppTypeFor<TypeCategory::Real, 16> x) {
751   return Nint<CppTypeFor<TypeCategory::Integer, 16>>(x);
752 }
753 #endif
754 #endif
755 
756 CppTypeFor<TypeCategory::Real, 4> RTNAME(RRSpacing4)(
757     CppTypeFor<TypeCategory::Real, 4> x) {
758   return RRSpacing<24>(x);
759 }
760 CppTypeFor<TypeCategory::Real, 8> RTNAME(RRSpacing8)(
761     CppTypeFor<TypeCategory::Real, 8> x) {
762   return RRSpacing<53>(x);
763 }
764 #if LDBL_MANT_DIG == 64
765 CppTypeFor<TypeCategory::Real, 10> RTNAME(RRSpacing10)(
766     CppTypeFor<TypeCategory::Real, 10> x) {
767   return RRSpacing<64>(x);
768 }
769 #elif LDBL_MANT_DIG == 113
770 CppTypeFor<TypeCategory::Real, 16> RTNAME(RRSpacing16)(
771     CppTypeFor<TypeCategory::Real, 16> x) {
772   return RRSpacing<113>(x);
773 }
774 #endif
775 
776 CppTypeFor<TypeCategory::Real, 4> RTNAME(SetExponent4)(
777     CppTypeFor<TypeCategory::Real, 4> x, std::int64_t p) {
778   return SetExponent(x, p);
779 }
780 CppTypeFor<TypeCategory::Real, 8> RTNAME(SetExponent8)(
781     CppTypeFor<TypeCategory::Real, 8> x, std::int64_t p) {
782   return SetExponent(x, p);
783 }
784 #if LDBL_MANT_DIG == 64
785 CppTypeFor<TypeCategory::Real, 10> RTNAME(SetExponent10)(
786     CppTypeFor<TypeCategory::Real, 10> x, std::int64_t p) {
787   return SetExponent(x, p);
788 }
789 #elif LDBL_MANT_DIG == 113
790 CppTypeFor<TypeCategory::Real, 16> RTNAME(SetExponent16)(
791     CppTypeFor<TypeCategory::Real, 16> x, std::int64_t p) {
792   return SetExponent(x, p);
793 }
794 #endif
795 
796 CppTypeFor<TypeCategory::Real, 4> RTNAME(Scale4)(
797     CppTypeFor<TypeCategory::Real, 4> x, std::int64_t p) {
798   return Scale(x, p);
799 }
800 CppTypeFor<TypeCategory::Real, 8> RTNAME(Scale8)(
801     CppTypeFor<TypeCategory::Real, 8> x, std::int64_t p) {
802   return Scale(x, p);
803 }
804 #if LDBL_MANT_DIG == 64
805 CppTypeFor<TypeCategory::Real, 10> RTNAME(Scale10)(
806     CppTypeFor<TypeCategory::Real, 10> x, std::int64_t p) {
807   return Scale(x, p);
808 }
809 #elif LDBL_MANT_DIG == 113
810 CppTypeFor<TypeCategory::Real, 16> RTNAME(Scale16)(
811     CppTypeFor<TypeCategory::Real, 16> x, std::int64_t p) {
812   return Scale(x, p);
813 }
814 #endif
815 
816 // SELECTED_INT_KIND
817 CppTypeFor<TypeCategory::Integer, 4> RTNAME(SelectedIntKind)(
818     const char *source, int line, void *x, int xKind) {
819 #ifdef __SIZEOF_INT128__
820   CppTypeFor<TypeCategory::Integer, 16> r =
821       getIntArgValue<CppTypeFor<TypeCategory::Integer, 16>>(
822           source, line, x, xKind, /*defaultValue*/ 0, /*resKind*/ 16);
823 #else
824   std::int64_t r = getIntArgValue<std::int64_t>(
825       source, line, x, xKind, /*defaultValue*/ 0, /*resKind*/ 8);
826 #endif
827   return SelectedIntKind(r);
828 }
829 
830 // SELECTED_REAL_KIND
831 CppTypeFor<TypeCategory::Integer, 4> RTNAME(SelectedRealKind)(
832     const char *source, int line, void *precision, int pKind, void *range,
833     int rKind, void *radix, int dKind) {
834 #ifdef __SIZEOF_INT128__
835   CppTypeFor<TypeCategory::Integer, 16> p =
836       getIntArgValue<CppTypeFor<TypeCategory::Integer, 16>>(
837           source, line, precision, pKind, /*defaultValue*/ 0, /*resKind*/ 16);
838   CppTypeFor<TypeCategory::Integer, 16> r =
839       getIntArgValue<CppTypeFor<TypeCategory::Integer, 16>>(
840           source, line, range, rKind, /*defaultValue*/ 0, /*resKind*/ 16);
841   CppTypeFor<TypeCategory::Integer, 16> d =
842       getIntArgValue<CppTypeFor<TypeCategory::Integer, 16>>(
843           source, line, radix, dKind, /*defaultValue*/ 2, /*resKind*/ 16);
844 #else
845   std::int64_t p = getIntArgValue<std::int64_t>(
846       source, line, precision, pKind, /*defaultValue*/ 0, /*resKind*/ 8);
847   std::int64_t r = getIntArgValue<std::int64_t>(
848       source, line, range, rKind, /*defaultValue*/ 0, /*resKind*/ 8);
849   std::int64_t d = getIntArgValue<std::int64_t>(
850       source, line, radix, dKind, /*defaultValue*/ 2, /*resKind*/ 8);
851 #endif
852   return SelectedRealKind(p, r, d);
853 }
854 
855 CppTypeFor<TypeCategory::Real, 4> RTNAME(Spacing4)(
856     CppTypeFor<TypeCategory::Real, 4> x) {
857   return Spacing<24>(x);
858 }
859 CppTypeFor<TypeCategory::Real, 8> RTNAME(Spacing8)(
860     CppTypeFor<TypeCategory::Real, 8> x) {
861   return Spacing<53>(x);
862 }
863 #if LDBL_MANT_DIG == 64
864 CppTypeFor<TypeCategory::Real, 10> RTNAME(Spacing10)(
865     CppTypeFor<TypeCategory::Real, 10> x) {
866   return Spacing<64>(x);
867 }
868 #elif LDBL_MANT_DIG == 113
869 CppTypeFor<TypeCategory::Real, 16> RTNAME(Spacing16)(
870     CppTypeFor<TypeCategory::Real, 16> x) {
871   return Spacing<113>(x);
872 }
873 #endif
874 } // extern "C"
875 } // namespace Fortran::runtime
876