xref: /netbsd-src/external/gpl3/gcc/dist/libgfortran/intrinsics/erfc_scaled.c (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1181254a7Smrg /* Implementation of the ERFC_SCALED intrinsic.
2*b1e83836Smrg    Copyright (C) 2008-2022 Free Software Foundation, Inc.
3181254a7Smrg 
4181254a7Smrg This file is part of the GNU Fortran runtime library (libgfortran).
5181254a7Smrg 
6181254a7Smrg Libgfortran is free software; you can redistribute it and/or
7181254a7Smrg modify it under the terms of the GNU General Public
8181254a7Smrg License as published by the Free Software Foundation; either
9181254a7Smrg version 3 of the License, or (at your option) any later version.
10181254a7Smrg 
11181254a7Smrg Libgfortran is distributed in the hope that it will be useful,
12181254a7Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
13181254a7Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14181254a7Smrg GNU General Public License for more details.
15181254a7Smrg 
16181254a7Smrg Under Section 7 of GPL version 3, you are granted additional
17181254a7Smrg permissions described in the GCC Runtime Library Exception, version
18181254a7Smrg 3.1, as published by the Free Software Foundation.
19181254a7Smrg 
20181254a7Smrg You should have received a copy of the GNU General Public License and
21181254a7Smrg a copy of the GCC Runtime Library Exception along with this program;
22181254a7Smrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23181254a7Smrg <http://www.gnu.org/licenses/>.  */
24181254a7Smrg 
25181254a7Smrg #include "libgfortran.h"
26181254a7Smrg 
27181254a7Smrg /* This implementation of ERFC_SCALED is based on the netlib algorithm
28181254a7Smrg    available at http://www.netlib.org/specfun/erf  */
29181254a7Smrg 
30181254a7Smrg #ifdef HAVE_GFC_REAL_4
31181254a7Smrg #undef KIND
32181254a7Smrg #define KIND 4
33181254a7Smrg #include "erfc_scaled_inc.c"
34181254a7Smrg #endif
35181254a7Smrg 
36181254a7Smrg #ifdef HAVE_GFC_REAL_8
37181254a7Smrg #undef KIND
38181254a7Smrg #define KIND 8
39181254a7Smrg #include "erfc_scaled_inc.c"
40181254a7Smrg #endif
41181254a7Smrg 
42181254a7Smrg #ifdef HAVE_GFC_REAL_10
43181254a7Smrg #undef KIND
44181254a7Smrg #define KIND 10
45181254a7Smrg #include "erfc_scaled_inc.c"
46181254a7Smrg #endif
47181254a7Smrg 
48181254a7Smrg #ifdef HAVE_GFC_REAL_16
49181254a7Smrg 
50181254a7Smrg /* For quadruple-precision, netlib's implementation is
51181254a7Smrg    not accurate enough.  We provide another one.  */
52181254a7Smrg 
53181254a7Smrg #ifdef GFC_REAL_16_IS_FLOAT128
54181254a7Smrg 
55181254a7Smrg # define _THRESH -106.566990228185312813205074546585730Q
56181254a7Smrg # define _M_2_SQRTPI M_2_SQRTPIq
57181254a7Smrg # define _INF __builtin_infq()
58181254a7Smrg # define _ERFC(x) erfcq(x)
59181254a7Smrg # define _EXP(x) expq(x)
60181254a7Smrg 
61181254a7Smrg #else
62181254a7Smrg 
63181254a7Smrg # define _THRESH -106.566990228185312813205074546585730L
64181254a7Smrg # ifndef M_2_SQRTPIl
65181254a7Smrg #  define M_2_SQRTPIl 1.128379167095512573896158903121545172L
66181254a7Smrg # endif
67181254a7Smrg # define _M_2_SQRTPI M_2_SQRTPIl
68181254a7Smrg # define _INF __builtin_infl()
69181254a7Smrg # ifdef HAVE_ERFCL
70181254a7Smrg #  define _ERFC(x) erfcl(x)
71181254a7Smrg # endif
72181254a7Smrg # ifdef HAVE_EXPL
73181254a7Smrg #  define _EXP(x) expl(x)
74181254a7Smrg # endif
75181254a7Smrg 
76181254a7Smrg #endif
77181254a7Smrg 
78*b1e83836Smrg #define ERFC_SCALED(k) \
79*b1e83836Smrg GFC_REAL_ ## k								    \
80*b1e83836Smrg erfc_scaled_r ## k (GFC_REAL_ ## k x)					    \
81*b1e83836Smrg {									    \
82*b1e83836Smrg   if (x < _THRESH)							    \
83*b1e83836Smrg     {									    \
84*b1e83836Smrg       return _INF;							    \
85*b1e83836Smrg     }									    \
86*b1e83836Smrg   if (x < 12)								    \
87*b1e83836Smrg     {									    \
88*b1e83836Smrg       /* Compute directly as ERFC_SCALED(x) = ERFC(x) * EXP(X**2).	    \
89*b1e83836Smrg 	 This is not perfect, but much better than netlib.  */		    \
90*b1e83836Smrg       return _ERFC(x) * _EXP(x * x);					    \
91*b1e83836Smrg     }									    \
92*b1e83836Smrg   else									    \
93*b1e83836Smrg     {									    \
94*b1e83836Smrg       /* Calculate ERFC_SCALED(x) using a power series in 1/x:		    \
95*b1e83836Smrg 	 ERFC_SCALED(x) = 1 / (x * sqrt(pi))				    \
96*b1e83836Smrg 			 * (1 + Sum_n (-1)**n * (1 * 3 * 5 * ... * (2n-1))  \
97*b1e83836Smrg 					      / (2 * x**2)**n)		    \
98*b1e83836Smrg        */								    \
99*b1e83836Smrg       GFC_REAL_ ## k sum = 0, oldsum;					    \
100*b1e83836Smrg       GFC_REAL_ ## k inv2x2 = 1 / (2 * x * x);				    \
101*b1e83836Smrg       GFC_REAL_ ## k fac = 1;						    \
102*b1e83836Smrg       int n = 1;							    \
103*b1e83836Smrg 									    \
104*b1e83836Smrg       while (n < 200)							    \
105*b1e83836Smrg 	{								    \
106*b1e83836Smrg 	  fac *= - (2*n - 1) * inv2x2;					    \
107*b1e83836Smrg 	  oldsum = sum;							    \
108*b1e83836Smrg 	  sum += fac;							    \
109*b1e83836Smrg 									    \
110*b1e83836Smrg 	  if (sum == oldsum)						    \
111*b1e83836Smrg 	    break;							    \
112*b1e83836Smrg 									    \
113*b1e83836Smrg 	  n++;								    \
114*b1e83836Smrg 	}								    \
115*b1e83836Smrg 									    \
116*b1e83836Smrg       return (1 + sum) / x * (_M_2_SQRTPI / 2);				    \
117*b1e83836Smrg     }									    \
118*b1e83836Smrg }
119*b1e83836Smrg 
120181254a7Smrg #if defined(_ERFC) && defined(_EXP)
121181254a7Smrg 
122181254a7Smrg extern GFC_REAL_16 erfc_scaled_r16 (GFC_REAL_16);
123181254a7Smrg export_proto(erfc_scaled_r16);
124181254a7Smrg 
125*b1e83836Smrg ERFC_SCALED(16)
126181254a7Smrg 
127181254a7Smrg #endif
128181254a7Smrg 
129*b1e83836Smrg #undef _THRESH
130*b1e83836Smrg #undef _M_2_SQRTPI
131*b1e83836Smrg #undef _INF
132*b1e83836Smrg #undef _ERFC
133*b1e83836Smrg #undef _EXP
134*b1e83836Smrg 
135*b1e83836Smrg #endif
136*b1e83836Smrg 
137*b1e83836Smrg #ifdef HAVE_GFC_REAL_17
138*b1e83836Smrg 
139*b1e83836Smrg /* For quadruple-precision, netlib's implementation is
140*b1e83836Smrg    not accurate enough.  We provide another one.  */
141*b1e83836Smrg 
142*b1e83836Smrg # define _THRESH -106.566990228185312813205074546585730Q
143*b1e83836Smrg # define _M_2_SQRTPI M_2_SQRTPIq
144*b1e83836Smrg # define _INF __builtin_inff128()
145*b1e83836Smrg # ifdef POWER_IEEE128
146*b1e83836Smrg #  define _ERFC(x) __erfcieee128(x)
147*b1e83836Smrg #  define _EXP(x) __expieee128(x)
148*b1e83836Smrg # else
149*b1e83836Smrg #  define _ERFC(x) erfcq(x)
150*b1e83836Smrg #  define _EXP(x) expq(x)
151*b1e83836Smrg # endif
152*b1e83836Smrg 
153*b1e83836Smrg extern GFC_REAL_17 erfc_scaled_r17 (GFC_REAL_17);
154*b1e83836Smrg export_proto(erfc_scaled_r17);
155*b1e83836Smrg 
156*b1e83836Smrg ERFC_SCALED(17)
157*b1e83836Smrg 
158*b1e83836Smrg #undef _THRESH
159*b1e83836Smrg #undef _M_2_SQRTPI
160*b1e83836Smrg #undef _INF
161*b1e83836Smrg #undef _ERFC
162*b1e83836Smrg #undef _EXP
163*b1e83836Smrg #undef ERFC_SCALED
164*b1e83836Smrg 
165181254a7Smrg #endif
166