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