2017-07-20 Richard Biener <rguenther@suse.de>
[official-gcc.git] / libgfortran / intrinsics / erfc_scaled.c
blob881033c60352f271d64881fad67aec2b754714d0
1 /* Implementation of the ERFC_SCALED intrinsic.
2 Copyright (C) 2008-2017 Free Software Foundation, Inc.
4 This file is part of the GNU Fortran runtime library (libgfortran).
6 Libgfortran is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public
8 License as published by the Free Software Foundation; either
9 version 3 of the License, or (at your option) any later version.
11 Libgfortran is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
25 #include "libgfortran.h"
27 /* This implementation of ERFC_SCALED is based on the netlib algorithm
28 available at http://www.netlib.org/specfun/erf */
30 #ifdef HAVE_GFC_REAL_4
31 #undef KIND
32 #define KIND 4
33 #include "erfc_scaled_inc.c"
34 #endif
36 #ifdef HAVE_GFC_REAL_8
37 #undef KIND
38 #define KIND 8
39 #include "erfc_scaled_inc.c"
40 #endif
42 #ifdef HAVE_GFC_REAL_10
43 #undef KIND
44 #define KIND 10
45 #include "erfc_scaled_inc.c"
46 #endif
48 #ifdef HAVE_GFC_REAL_16
50 /* For quadruple-precision, netlib's implementation is
51 not accurate enough. We provide another one. */
53 #ifdef GFC_REAL_16_IS_FLOAT128
55 # define _THRESH -106.566990228185312813205074546585730Q
56 # define _M_2_SQRTPI M_2_SQRTPIq
57 # define _INF __builtin_infq()
58 # define _ERFC(x) erfcq(x)
59 # define _EXP(x) expq(x)
61 #else
63 # define _THRESH -106.566990228185312813205074546585730L
64 # ifndef M_2_SQRTPIl
65 # define M_2_SQRTPIl 1.128379167095512573896158903121545172L
66 # endif
67 # define _M_2_SQRTPI M_2_SQRTPIl
68 # define _INF __builtin_infl()
69 # ifdef HAVE_ERFCL
70 # define _ERFC(x) erfcl(x)
71 # endif
72 # ifdef HAVE_EXPL
73 # define _EXP(x) expl(x)
74 # endif
76 #endif
78 #if defined(_ERFC) && defined(_EXP)
80 extern GFC_REAL_16 erfc_scaled_r16 (GFC_REAL_16);
81 export_proto(erfc_scaled_r16);
83 GFC_REAL_16
84 erfc_scaled_r16 (GFC_REAL_16 x)
86 if (x < _THRESH)
88 return _INF;
90 if (x < 12)
92 /* Compute directly as ERFC_SCALED(x) = ERFC(x) * EXP(X**2).
93 This is not perfect, but much better than netlib. */
94 return _ERFC(x) * _EXP(x * x);
96 else
98 /* Calculate ERFC_SCALED(x) using a power series in 1/x:
99 ERFC_SCALED(x) = 1 / (x * sqrt(pi))
100 * (1 + Sum_n (-1)**n * (1 * 3 * 5 * ... * (2n-1))
101 / (2 * x**2)**n)
103 GFC_REAL_16 sum = 0, oldsum;
104 GFC_REAL_16 inv2x2 = 1 / (2 * x * x);
105 GFC_REAL_16 fac = 1;
106 int n = 1;
108 while (n < 200)
110 fac *= - (2*n - 1) * inv2x2;
111 oldsum = sum;
112 sum += fac;
114 if (sum == oldsum)
115 break;
117 n++;
120 return (1 + sum) / x * (_M_2_SQRTPI / 2);
124 #endif
126 #endif