FLANG
erfc-scaled.h
1//===-- include/flang/Common/erfc-scaled.h-----------------------*- C++ -*-===//
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#ifndef FORTRAN_COMMON_ERFC_SCALED_H_
10#define FORTRAN_COMMON_ERFC_SCALED_H_
11
12#include "flang/Common/api-attrs.h"
13#include <cmath>
14#include <limits>
15
16namespace Fortran::common {
17template <typename T> inline RT_API_ATTRS T ErfcScaled(T arg) {
18 // Coefficients for approximation to erfc in the first interval.
19 static const T a[5] = {3.16112374387056560e00, 1.13864154151050156e02,
20 3.77485237685302021e02, 3.20937758913846947e03, 1.85777706184603153e-1};
21 static const T b[4] = {2.36012909523441209e01, 2.44024637934444173e02,
22 1.28261652607737228e03, 2.84423683343917062e03};
23
24 // Coefficients for approximation to erfc in the second interval.
25 static const T c[9] = {5.64188496988670089e-1, 8.88314979438837594e00,
26 6.61191906371416295e01, 2.98635138197400131e02, 8.81952221241769090e02,
27 1.71204761263407058e03, 2.05107837782607147e03, 1.23033935479799725e03,
28 2.15311535474403846e-8};
29 static const T d[8] = {1.57449261107098347e01, 1.17693950891312499e02,
30 5.37181101862009858e02, 1.62138957456669019e03, 3.29079923573345963e03,
31 4.36261909014324716e03, 3.43936767414372164e03, 1.23033935480374942e03};
32
33 // Coefficients for approximation to erfc in the third interval.
34 static const T p[6] = {3.05326634961232344e-1, 3.60344899949804439e-1,
35 1.25781726111229246e-1, 1.60837851487422766e-2, 6.58749161529837803e-4,
36 1.63153871373020978e-2};
37 static const T q[5] = {2.56852019228982242e00, 1.87295284992346047e00,
38 5.27905102951428412e-1, 6.05183413124413191e-2, 2.33520497626869185e-3};
39
40 constexpr T sqrtpi{1.7724538509078120380404576221783883301349L};
41 constexpr T rsqrtpi{0.5641895835477562869480794515607725858440L};
42 constexpr T epsilonby2{std::numeric_limits<T>::epsilon() * 0.5};
43 constexpr T xneg{-26.628e0};
44 constexpr T xhuge{6.71e7};
45 constexpr T thresh{0.46875e0};
46 constexpr T zero{0.0};
47 constexpr T one{1.0};
48 constexpr T four{4.0};
49 constexpr T sixteen{16.0};
50 constexpr T xmax{1.0 / (sqrtpi * std::numeric_limits<T>::min())};
51 static_assert(xmax > xhuge, "xmax must be greater than xhuge");
52
53 T ysq;
54 T xnum;
55 T xden;
56 T del;
57 T result;
58
59 auto x{arg};
60 auto y{std::fabs(x)};
61
62 if (y <= thresh) {
63 // evaluate erf for |x| <= 0.46875
64 ysq = zero;
65 if (y > epsilonby2) {
66 ysq = y * y;
67 }
68 xnum = a[4] * ysq;
69 xden = ysq;
70 for (int i{0}; i < 3; i++) {
71 xnum = (xnum + a[i]) * ysq;
72 xden = (xden + b[i]) * ysq;
73 }
74 result = x * (xnum + a[3]) / (xden + b[3]);
75 result = one - result;
76 result = std::exp(ysq) * result;
77 return result;
78 } else if (y <= four) {
79 // evaluate erfc for 0.46875 < |x| <= 4.0
80 xnum = c[8] * y;
81 xden = y;
82 for (int i{0}; i < 7; ++i) {
83 xnum = (xnum + c[i]) * y;
84 xden = (xden + d[i]) * y;
85 }
86 result = (xnum + c[7]) / (xden + d[7]);
87 } else {
88 // evaluate erfc for |x| > 4.0
89 result = zero;
90 if (y >= xhuge) {
91 if (y < xmax) {
92 result = rsqrtpi / y;
93 }
94 } else {
95 ysq = one / (y * y);
96 xnum = p[5] * ysq;
97 xden = ysq;
98 for (int i{0}; i < 4; ++i) {
99 xnum = (xnum + p[i]) * ysq;
100 xden = (xden + q[i]) * ysq;
101 }
102 result = ysq * (xnum + p[4]) / (xden + q[4]);
103 result = (rsqrtpi - result) / y;
104 }
105 }
106 // fix up for negative argument, erf, etc.
107 if (x < zero) {
108 if (x < xneg) {
109 result = std::numeric_limits<T>::max();
110 } else {
111 ysq = trunc(x * sixteen) / sixteen;
112 del = (x - ysq) * (x + ysq);
113 y = std::exp((ysq * ysq)) * std::exp((del));
114 result = (y + y) - result;
115 }
116 }
117 return result;
118}
119} // namespace Fortran::common
120#endif // FORTRAN_COMMON_ERFC_SCALED_H_
Definition bit-population-count.h:20