18#ifndef FORTRAN_RUNTIME_NUMERIC_TEMPLATES_H_
19#define FORTRAN_RUNTIME_NUMERIC_TEMPLATES_H_
21#include "terminator.h"
23#include "flang/Common/api-attrs.h"
24#include "flang/Common/erfc-scaled.h"
25#include "flang/Common/float128.h"
29namespace Fortran::runtime {
34template <TypeCategory CAT,
int KIND,
bool IS_MAXVAL,
typename Enable =
void>
36 using Type = CppTypeFor<CAT, KIND>;
37 static constexpr RT_API_ATTRS Type Value() {
38 return IS_MAXVAL ? std::numeric_limits<Type>::lowest()
39 : std::numeric_limits<Type>::max();
44template <
bool IS_MAXVAL>
46 using Type = CppTypeFor<TypeCategory::Integer, 16>;
47 static constexpr RT_API_ATTRS Type Value() {
48 return IS_MAXVAL ? Type{1} << 127 : ~Type{0} >> 1;
61template <
bool IS_MAXVAL>
63 typename std::enable_if_t<
64 std::is_same_v<CppTypeFor<TypeCategory::Real, 16>, __float128>>> {
65 using Type = __float128;
66 static RT_API_ATTRS Type Value() {
68 constexpr std::size_t alignment =
69 std::max(
alignof(Type),
alignof(std::uint64_t));
70 alignas(alignment)
char data[
sizeof(Type)];
74 *
reinterpret_cast<Type *
>(data) = Type(1.0);
75 if (*
reinterpret_cast<std::uint64_t *
>(data) != 0 ||
76 *(
reinterpret_cast<std::uint64_t *
>(data) + 1) != 0x3FFF000000000000) {
78 terminator.Crash(
"not yet implemented: no full support for __float128");
82 *
reinterpret_cast<std::uint64_t *
>(data) = 0xFFFFFFFFFFFFFFFF;
83 *(
reinterpret_cast<std::uint64_t *
>(data) + 1) = 0x7FFEFFFFFFFFFFFF;
84 Type max = *
reinterpret_cast<Type *
>(data);
85 return IS_MAXVAL ? -max : max;
92template <
int PREC,
typename T>
struct MinValue {
93 static RT_API_ATTRS T get() {
return std::numeric_limits<T>::min(); }
97 static constexpr RT_API_ATTRS T get() {
return 0.00006103515625E-04; }
101template <>
struct MinValue<113, CppTypeFor<TypeCategory::Real, 16>> {
102 using Type = CppTypeFor<TypeCategory::Real, 16>;
103 static RT_API_ATTRS Type get() {
105 constexpr std::size_t alignment =
106 std::max(
alignof(Type),
alignof(std::uint64_t));
107 alignas(alignment)
char data[
sizeof(Type)];
111 *
reinterpret_cast<Type *
>(data) = Type(1.0);
112 if (*
reinterpret_cast<std::uint64_t *
>(data) != 0 ||
113 *(
reinterpret_cast<std::uint64_t *
>(data) + 1) != 0x3FFF000000000000) {
115 terminator.Crash(
"not yet implemented: no full support for __float128");
119 *
reinterpret_cast<std::uint64_t *
>(data) = 0;
120 *(
reinterpret_cast<std::uint64_t *
>(data) + 1) = 0x1000000000000;
121 return *
reinterpret_cast<Type *
>(data);
127 static constexpr RT_API_ATTRS T compute(T x) {
return std::abs(x); }
133RT_DIAG_DISABLE_CALL_HOST_FROM_DEVICE_WARN
136 static constexpr RT_API_ATTRS T compute(T x,
int *e) {
137 return std::frexp(x, e);
144 static constexpr RT_API_ATTRS
int compute(T x) {
return std::ilogb(x); }
148 static constexpr RT_API_ATTRS
bool compute(T x) {
return std::isinf(x); }
152 static constexpr RT_API_ATTRS
bool compute(T x) {
return std::isnan(x); }
156 template <
typename ET>
static constexpr RT_API_ATTRS T compute(T x, ET e) {
157 return std::ldexp(x, e);
162 static constexpr RT_API_ATTRS T compute() {
163 return std::numeric_limits<T>::max();
167#if HAS_LDBL128 || HAS_FLOAT128
168template <>
struct MAXTy<CppTypeFor<TypeCategory::Real, 16>> {
169 static CppTypeFor<TypeCategory::Real, 16> compute() {
175template <
int PREC,
typename T>
struct MINTy {
180 static constexpr RT_API_ATTRS T compute() {
181 return std::numeric_limits<T>::quiet_NaN();
186 static constexpr RT_API_ATTRS T compute(T x) {
return std::sqrt(x); }
190template <
typename RESULT,
typename ARG>
191inline RT_API_ATTRS RESULT Exponent(ARG x) {
197 return ILOGBTy<ARG>::compute(x) + 1;
202template <
typename T>
inline RT_API_ATTRS T Fraction(T x) {
203 if (ISNANTy<T>::compute(x)) {
205 }
else if (ISINFTy<T>::compute(x)) {
206 return QNANTy<T>::compute();
211 return FREXPTy<T>::compute(x, &ignoredExp);
216template <
typename T>
inline RT_API_ATTRS T SetExponent(T x, std::int64_t p) {
217 if (ISNANTy<T>::compute(x)) {
219 }
else if (ISINFTy<T>::compute(x)) {
220 return QNANTy<T>::compute();
224 int expo{ILOGBTy<T>::compute(x) + 1};
225 auto ip{
static_cast<int>(p - expo)};
226 if (ip != p - expo) {
227 ip = p < 0 ? std::numeric_limits<int>::min()
228 : std::numeric_limits<int>::max();
230 return LDEXPTy<T>::compute(x, ip);
235template <
bool IS_MODULO,
typename T>
236inline RT_API_ATTRS T RealMod(
237 T a, T p,
const char *sourceFile,
int sourceLine) {
239 Terminator{sourceFile, sourceLine}.Crash(
240 IS_MODULO ?
"MODULO with P==0" :
"MOD with P==0");
242 if (ISNANTy<T>::compute(a) || ISNANTy<T>::compute(p) ||
243 ISINFTy<T>::compute(a)) {
244 return QNANTy<T>::compute();
245 }
else if (IS_MODULO && ISINFTy<T>::compute(p)) {
250 return QNANTy<T>::compute();
252 T aAbs{ABSTy<T>::compute(a)};
253 T pAbs{ABSTy<T>::compute(p)};
254 if (aAbs <=
static_cast<T
>(std::numeric_limits<std::int64_t>::max()) &&
255 pAbs <=
static_cast<T
>(std::numeric_limits<std::int64_t>::max())) {
256 if (
auto aInt{
static_cast<std::int64_t
>(a)}; a == aInt) {
257 if (
auto pInt{
static_cast<std::int64_t
>(p)}; p == pInt) {
259 auto mod{aInt - (aInt / pInt) * pInt};
260 if constexpr (IS_MODULO) {
263 return pInt > 0 ? T{0} : -T{0};
265 if ((aInt > 0) != (pInt > 0)) {
271 return aInt > 0 ? T{0} : -T{0};
274 return static_cast<T
>(mod);
278 if constexpr (std::is_same_v<T, float> || std::is_same_v<T, double> ||
279 std::is_same_v<T, long double>) {
282 T result{std::fmod(a, p)};
283 if constexpr (IS_MODULO) {
284 if ((a < 0) != (p < 0)) {
307 for (T adj{SetExponent(pAbs, Exponent<int>(aAbs))}; tmp >= pAbs; adj /= 2) {
318 if constexpr (IS_MODULO) {
319 if ((a < 0) != (p < 0)) {
332template <
int PREC,
typename T>
inline RT_API_ATTRS T RRSpacing(T x) {
333 if (ISNANTy<T>::compute(x)) {
335 }
else if (ISINFTy<T>::compute(x)) {
336 return QNANTy<T>::compute();
340 return LDEXPTy<T>::compute(
341 ABSTy<T>::compute(x), PREC - (ILOGBTy<T>::compute(x) + 1));
346template <
int PREC,
typename T>
inline RT_API_ATTRS T Spacing(T x) {
347 T tiny{MINTy<PREC, T>::compute()};
348 if (ISNANTy<T>::compute(x)) {
350 }
else if (ISINFTy<T>::compute(x)) {
351 return QNANTy<T>::compute();
355 T result{LDEXPTy<T>::compute(
356 static_cast<T
>(1.0), ILOGBTy<T>::compute(x) + 1 - PREC)};
360 return result <= tiny ? tiny : result;
365template <
typename T>
inline RT_API_ATTRS T ErfcScaled(T arg) {
366 return common::ErfcScaled(arg);
Definition: terminator.h:23
Definition: numeric-templates.h:126
Definition: numeric-templates.h:135
Definition: numeric-templates.h:143
Definition: numeric-templates.h:147
Definition: numeric-templates.h:151
Definition: numeric-templates.h:155
Definition: numeric-templates.h:161
Definition: numeric-templates.h:175
Definition: numeric-templates.h:35
Definition: numeric-templates.h:92
Definition: numeric-templates.h:179
Definition: numeric-templates.h:185