!******************************************************************************* ! Obtain erfc(x) (and erf(x)) to the maximum machine accuracy possible. ! ! REFERENCE: Irene A. Stegun and Ruth Zucker, J. Res. NBS 74B, 211-224 (1970). ! ``Automatic Computing Methods for Special Functions'', ! Part 1. Error, Probability, and Related Functions ! ! CARDS GIVEN AS DOUBLE PRECISION CONSTANTS, YIELDS DOUBLE ! PRECISION RESULTS ON THE UNIVAC 1108 SYSTEM. ! ! SINGLE PRECISION RESULTS ARE OBTAINED BY ! (1) DELETING THE TYPE STATEMENT ! (2) SETTING NBC=8, NBM=27 ON THE FIRST DATA CARD ! (3) CHANGING THE D'S TO E'S ON THE SECOND AND THIRD DATA ! CARDS. ! (4) CHANGING THE FUNCTION TYPE - DABS TO ABS, DEXP TO EXP ! ! FOR OTHER VALUES OF NBM, THE CONSTANT ON THE THIRD DATA ! CARD SHOULD BE GIVEN TO THE CORRESPONDING PRECISION. ! ! NBC: Number of binary digits in the characteristic of a floating ! point number. ! Single precision: NBC = 8, Double precision, NBC = 11 ! NBM: Accuracy desired or maximum number of binary digits in the ! mantissa of a floating point number. ! Single precision: NBM = 11, Double precision, NBM = 60 ! ! METHOD: Power series for ABS(X) <= 1 (= ULPS, upper limit for series). ! Continued fraction for ULPS < ABS(X) <= ULCF ! (ULCF = upper limit of continued fraction) ! ! RANGE: ABS(X) <= ULCF ; ULCF = 0.83*(2.0**((NBC-1)/2)) ! ABS(ULCF) approximately 9.3 for NBC = 8 ! 26.5 for NBC = 11 ! Beyond this range the limiting values of the functions are ! supplied: ERF(INF) = 1.0, ERFC(INF) = 0.0 ! ! ACCURACY: Routine will return (NBM-I-3) significant binary digits ! where I is the number of binary digits representing the ! integer part of X**2. (This is essentially the accuracy of ! the exponential routine.) ! ! PRECISION: Variable - by setting desired NBM !******************************************************************************* function erfc05(x) result(erfc) use precision, only: wp implicit none real(wp), intent(in) :: x real(wp) :: erf,erfc real(wp) :: an,bn,c1,dn,f,fn, & fnm1,fnm2,gn,gnm1,gnm2, & prev,pwr,rnbc,scf,sum,tn,toler, & ulcf,wn,y,ysq integer, parameter :: nbc = 11 integer, parameter :: nbm = 60 real(wp), parameter :: zero = 0.0_wp real(wp), parameter :: one = 1.0_wp real(wp), parameter :: two = 2.0_wp real(wp), parameter :: four = 4.0_wp real(wp), parameter :: ulps = 1.0_wp real(wp), parameter :: cons = 0.83_wp real(wp), parameter :: trrtpi = 1.128379167095512574_wp rnbc = nbc toler = two**(-nbm) ! Test on zero if (x == zero) then erf = zero erfc = one return endif y = abs(x) ysq = y**2 if (y <= ulps) then ! Method: power series sum = zero dn = one tn = one pwr = two*ysq do dn = dn + two tn = pwr*tn/dn sum = tn + sum ! Tolerance check if (tn < toler) exit enddo erf = (sum + one)*trrtpi*y*exp(-ysq) erfc = one - erf else ! Maximum argument c1 = two**((rnbc-one)/two) ulcf = cons*c1 ! Scale factor scf = two**(c1**2 - rnbc) ! Limiting value if (y > ulcf) then erf = one erfc = zero else ! Method: continued fraction fnm2 = zero gnm2 = one fnm1 = two*y gnm1 = two*ysq + one prev = fnm1/gnm1 wn = one bn = gnm1 + four do an = -wn*(wn + one) fn = bn*fnm1 + an*fnm2 gn = bn*gnm1 + an*gnm2 f = fn/gn ! Tolerance check if (abs(one - (f/prev)) <= toler) exit if (prev > f) then f = prev exit endif ! Both fn and gn must be tested if abs(x) < 0.61 if (gn >= scf) then ! Scaling fn = fn/scf gn = gn/scf fnm1 = fnm1/scf gnm1 = gnm1/scf endif fnm2 = fnm1 gnm2 = gnm1 fnm1 = fn gnm1 = gn wn = wn + two bn = bn + four prev = f enddo erfc = f*exp(-ysq)*trrtpi/two erf = one - erfc endif endif ! Negative argument if (x < zero) erfc = two - erfc ! if (x < zero) erf = -erf end function erfc05