1 !------------------------------------------------------------------------
2 ! Based on error_function.F90 from CAM
3 ! Ported to WRF by William.Gustafson@pnl.gov, Dec. 2009
4 !------------------------------------------------------------------------
8 ! This module provides generic interfaces for functions that evaluate
9 ! erf(x), erfc(x), and exp(x*x)*erfc(x) in either single or double precision.
16 public :: erf, erfc, erfcx
19 module procedure erf_r4
24 module procedure erfc_r4
25 module procedure derfc
29 module procedure erfcx_r4
30 module procedure derfcx
34 integer, parameter :: r4 = selected_real_kind(6) ! 4 byte real
35 integer, parameter :: r8 = selected_real_kind(12) ! 8 byte real
39 !------------------------------------------------------------------
41 ! 6 December 2006 -- B. Eaton
42 ! The following comments are from the original version of CALERF.
43 ! The only changes in implementing this module are that the function
44 ! names previously used for the single precision versions have been
45 ! adopted for the new generic interfaces. To support these interfaces
46 ! there is now both a single precision version (calerf_r4) and a
47 ! double precision version (calerf_r8) of CALERF below. These versions
48 ! are hardcoded to use IEEE arithmetic.
50 !------------------------------------------------------------------
52 ! This packet evaluates erf(x), erfc(x), and exp(x*x)*erfc(x)
53 ! for a real argument x. It contains three FUNCTION type
54 ! subprograms: ERF, ERFC, and ERFCX (or DERF, DERFC, and DERFCX),
55 ! and one SUBROUTINE type subprogram, CALERF. The calling
56 ! statements for the primary entries are:
58 ! Y=ERF(X) (or Y=DERF(X)),
60 ! Y=ERFC(X) (or Y=DERFC(X)),
62 ! Y=ERFCX(X) (or Y=DERFCX(X)).
64 ! The routine CALERF is intended for internal packet use only,
65 ! all computations within the packet being concentrated in this
66 ! routine. The function subprograms invoke CALERF with the
69 ! CALL CALERF(ARG,RESULT,JINT)
71 ! where the parameter usage is as follows
73 ! Function Parameters for CALERF
74 ! call ARG Result JINT
76 ! ERF(ARG) ANY REAL ARGUMENT ERF(ARG) 0
77 ! ERFC(ARG) ABS(ARG) .LT. XBIG ERFC(ARG) 1
78 ! ERFCX(ARG) XNEG .LT. ARG .LT. XMAX ERFCX(ARG) 2
80 ! The main computation evaluates near-minimax approximations
81 ! from "Rational Chebyshev approximations for the error function"
82 ! by W. J. Cody, Math. Comp., 1969, PP. 631-638. This
83 ! transportable program uses rational functions that theoretically
84 ! approximate erf(x) and erfc(x) to at least 18 significant
85 ! decimal digits. The accuracy achieved depends on the arithmetic
86 ! system, the compiler, the intrinsic functions, and proper
87 ! selection of the machine-dependent constants.
89 !*******************************************************************
90 !*******************************************************************
92 ! Explanation of machine-dependent constants
94 ! XMIN = the smallest positive floating-point number.
95 ! XINF = the largest positive finite floating-point number.
96 ! XNEG = the largest negative argument acceptable to ERFCX;
97 ! the negative of the solution to the equation
99 ! XSMALL = argument below which erf(x) may be represented by
100 ! 2*x/sqrt(pi) and above which x*x will not underflow.
101 ! A conservative value is the largest machine number X
102 ! such that 1.0 + X = 1.0 to machine precision.
103 ! XBIG = largest argument acceptable to ERFC; solution to
104 ! the equation: W(x) * (1-0.5/x**2) = XMIN, where
105 ! W(x) = exp(-x*x)/[x*sqrt(pi)].
106 ! XHUGE = argument above which 1.0 - 1/(2*x*x) = 1.0 to
107 ! machine precision. A conservative value is
109 ! XMAX = largest acceptable argument to ERFCX; the minimum
110 ! of XINF and 1/[sqrt(pi)*XMIN].
112 ! Approximate values for some important machines are:
114 ! XMIN XINF XNEG XSMALL
116 ! CDC 7600 (S.P.) 3.13E-294 1.26E+322 -27.220 7.11E-15
117 ! CRAY-1 (S.P.) 4.58E-2467 5.45E+2465 -75.345 7.11E-15
119 ! SUN, etc.) (S.P.) 1.18E-38 3.40E+38 -9.382 5.96E-8
121 ! SUN, etc.) (D.P.) 2.23D-308 1.79D+308 -26.628 1.11D-16
122 ! IBM 195 (D.P.) 5.40D-79 7.23E+75 -13.190 1.39D-17
123 ! UNIVAC 1108 (D.P.) 2.78D-309 8.98D+307 -26.615 1.73D-18
124 ! VAX D-Format (D.P.) 2.94D-39 1.70D+38 -9.345 1.39D-17
125 ! VAX G-Format (D.P.) 5.56D-309 8.98D+307 -26.615 1.11D-16
130 ! CDC 7600 (S.P.) 25.922 8.39E+6 1.80X+293
131 ! CRAY-1 (S.P.) 75.326 8.39E+6 5.45E+2465
133 ! SUN, etc.) (S.P.) 9.194 2.90E+3 4.79E+37
135 ! SUN, etc.) (D.P.) 26.543 6.71D+7 2.53D+307
136 ! IBM 195 (D.P.) 13.306 1.90D+8 7.23E+75
137 ! UNIVAC 1108 (D.P.) 26.582 5.37D+8 8.98D+307
138 ! VAX D-Format (D.P.) 9.269 1.90D+8 1.70D+38
139 ! VAX G-Format (D.P.) 26.569 6.71D+7 8.98D+307
141 !*******************************************************************
142 !*******************************************************************
146 ! The program returns ERFC = 0 for ARG .GE. XBIG;
148 ! ERFCX = XINF for ARG .LT. XNEG;
150 ! ERFCX = 0 for ARG .GE. XMAX.
153 ! Intrinsic functions required are:
159 ! Mathematics and Computer Science Division
160 ! Argonne National Laboratory
163 ! Latest modification: March 19, 1990
165 !------------------------------------------------------------------
167 SUBROUTINE CALERF_r8(ARG, RESULT, JINT)
169 !------------------------------------------------------------------
170 ! This version uses 8-byte reals
171 !------------------------------------------------------------------
172 integer, parameter :: rk = r8
175 real(rk), intent(in) :: arg
176 integer, intent(in) :: jint
177 real(rk), intent(out) :: result
182 real(rk) :: X, Y, YSQ, XNUM, XDEN, DEL
184 !------------------------------------------------------------------
185 ! Mathematical constants
186 !------------------------------------------------------------------
187 real(rk), parameter :: ZERO = 0.0E0_rk
188 real(rk), parameter :: FOUR = 4.0E0_rk
189 real(rk), parameter :: ONE = 1.0E0_rk
190 real(rk), parameter :: HALF = 0.5E0_rk
191 real(rk), parameter :: TWO = 2.0E0_rk
192 real(rk), parameter :: SQRPI = 5.6418958354775628695E-1_rk
193 real(rk), parameter :: THRESH = 0.46875E0_rk
194 real(rk), parameter :: SIXTEN = 16.0E0_rk
196 !------------------------------------------------------------------
197 ! Machine-dependent constants: IEEE single precision values
198 !------------------------------------------------------------------
199 !S real, parameter :: XINF = 3.40E+38
200 !S real, parameter :: XNEG = -9.382E0
201 !S real, parameter :: XSMALL = 5.96E-8
202 !S real, parameter :: XBIG = 9.194E0
203 !S real, parameter :: XHUGE = 2.90E3
204 !S real, parameter :: XMAX = 4.79E37
206 !------------------------------------------------------------------
207 ! Machine-dependent constants: IEEE double precision values
208 !------------------------------------------------------------------
209 real(rk), parameter :: XINF = 1.79E308_r8
210 real(rk), parameter :: XNEG = -26.628E0_r8
211 real(rk), parameter :: XSMALL = 1.11E-16_r8
212 real(rk), parameter :: XBIG = 26.543E0_r8
213 real(rk), parameter :: XHUGE = 6.71E7_r8
214 real(rk), parameter :: XMAX = 2.53E307_r8
216 !------------------------------------------------------------------
217 ! Coefficients for approximation to erf in first interval
218 !------------------------------------------------------------------
219 real(rk), parameter :: A(5) = (/ 3.16112374387056560E00_rk, 1.13864154151050156E02_rk, &
220 3.77485237685302021E02_rk, 3.20937758913846947E03_rk, &
221 1.85777706184603153E-1_rk /)
222 real(rk), parameter :: B(4) = (/ 2.36012909523441209E01_rk, 2.44024637934444173E02_rk, &
223 1.28261652607737228E03_rk, 2.84423683343917062E03_rk /)
225 !------------------------------------------------------------------
226 ! Coefficients for approximation to erfc in second interval
227 !------------------------------------------------------------------
228 real(rk), parameter :: C(9) = (/ 5.64188496988670089E-1_rk, 8.88314979438837594E00_rk, &
229 6.61191906371416295E01_rk, 2.98635138197400131E02_rk, &
230 8.81952221241769090E02_rk, 1.71204761263407058E03_rk, &
231 2.05107837782607147E03_rk, 1.23033935479799725E03_rk, &
232 2.15311535474403846E-8_rk /)
233 real(rk), parameter :: D(8) = (/ 1.57449261107098347E01_rk, 1.17693950891312499E02_rk, &
234 5.37181101862009858E02_rk, 1.62138957456669019E03_rk, &
235 3.29079923573345963E03_rk, 4.36261909014324716E03_rk, &
236 3.43936767414372164E03_rk, 1.23033935480374942E03_rk /)
238 !------------------------------------------------------------------
239 ! Coefficients for approximation to erfc in third interval
240 !------------------------------------------------------------------
241 real(rk), parameter :: P(6) = (/ 3.05326634961232344E-1_rk, 3.60344899949804439E-1_rk, &
242 1.25781726111229246E-1_rk, 1.60837851487422766E-2_rk, &
243 6.58749161529837803E-4_rk, 1.63153871373020978E-2_rk /)
244 real(rk), parameter :: Q(5) = (/ 2.56852019228982242E00_rk, 1.87295284992346047E00_rk, &
245 5.27905102951428412E-1_rk, 6.05183413124413191E-2_rk, &
246 2.33520497626869185E-3_rk /)
248 !------------------------------------------------------------------
251 IF (Y .LE. THRESH) THEN
252 !------------------------------------------------------------------
253 ! Evaluate erf for |X| <= 0.46875
254 !------------------------------------------------------------------
256 IF (Y .GT. XSMALL) YSQ = Y * Y
260 XNUM = (XNUM + A(I)) * YSQ
261 XDEN = (XDEN + B(I)) * YSQ
263 RESULT = X * (XNUM + A(4)) / (XDEN + B(4))
264 IF (JINT .NE. 0) RESULT = ONE - RESULT
265 IF (JINT .EQ. 2) RESULT = EXP(YSQ) * RESULT
267 ELSE IF (Y .LE. FOUR) THEN
268 !------------------------------------------------------------------
269 ! Evaluate erfc for 0.46875 <= |X| <= 4.0
270 !------------------------------------------------------------------
274 XNUM = (XNUM + C(I)) * Y
275 XDEN = (XDEN + D(I)) * Y
277 RESULT = (XNUM + C(8)) / (XDEN + D(8))
278 IF (JINT .NE. 2) THEN
279 YSQ = AINT(Y*SIXTEN)/SIXTEN
280 DEL = (Y-YSQ)*(Y+YSQ)
281 RESULT = EXP(-YSQ*YSQ) * EXP(-DEL) * RESULT
284 !------------------------------------------------------------------
285 ! Evaluate erfc for |X| > 4.0
286 !------------------------------------------------------------------
288 IF (Y .GE. XBIG) THEN
289 IF ((JINT .NE. 2) .OR. (Y .GE. XMAX)) GO TO 30
290 IF (Y .GE. XHUGE) THEN
299 XNUM = (XNUM + P(I)) * YSQ
300 XDEN = (XDEN + Q(I)) * YSQ
302 RESULT = YSQ *(XNUM + P(5)) / (XDEN + Q(5))
303 RESULT = (SQRPI - RESULT) / Y
304 IF (JINT .NE. 2) THEN
305 YSQ = AINT(Y*SIXTEN)/SIXTEN
306 DEL = (Y-YSQ)*(Y+YSQ)
307 RESULT = EXP(-YSQ*YSQ) * EXP(-DEL) * RESULT
311 !------------------------------------------------------------------
312 ! Fix up for negative argument, erf, etc.
313 !------------------------------------------------------------------
314 IF (JINT .EQ. 0) THEN
315 RESULT = (HALF - RESULT) + HALF
316 IF (X .LT. ZERO) RESULT = -RESULT
317 ELSE IF (JINT .EQ. 1) THEN
318 IF (X .LT. ZERO) RESULT = TWO - RESULT
320 IF (X .LT. ZERO) THEN
321 IF (X .LT. XNEG) THEN
324 YSQ = AINT(X*SIXTEN)/SIXTEN
325 DEL = (X-YSQ)*(X+YSQ)
326 Y = EXP(YSQ*YSQ) * EXP(DEL)
327 RESULT = (Y+Y) - RESULT
332 end SUBROUTINE CALERF_r8
334 !------------------------------------------------------------------------------------------
336 SUBROUTINE CALERF_r4(ARG, RESULT, JINT)
338 !------------------------------------------------------------------
339 ! This version uses 4-byte reals
340 !------------------------------------------------------------------
341 integer, parameter :: rk = r4
344 real(rk), intent(in) :: arg
345 integer, intent(in) :: jint
346 real(rk), intent(out) :: result
351 real(rk) :: X, Y, YSQ, XNUM, XDEN, DEL
353 !------------------------------------------------------------------
354 ! Mathematical constants
355 !------------------------------------------------------------------
356 real(rk), parameter :: ZERO = 0.0E0_rk
357 real(rk), parameter :: FOUR = 4.0E0_rk
358 real(rk), parameter :: ONE = 1.0E0_rk
359 real(rk), parameter :: HALF = 0.5E0_rk
360 real(rk), parameter :: TWO = 2.0E0_rk
361 real(rk), parameter :: SQRPI = 5.6418958354775628695E-1_rk
362 real(rk), parameter :: THRESH = 0.46875E0_rk
363 real(rk), parameter :: SIXTEN = 16.0E0_rk
365 !------------------------------------------------------------------
366 ! Machine-dependent constants: IEEE single precision values
367 !------------------------------------------------------------------
368 real(rk), parameter :: XINF = 3.40E+38_r4
369 real(rk), parameter :: XNEG = -9.382E0_r4
370 real(rk), parameter :: XSMALL = 5.96E-8_r4
371 real(rk), parameter :: XBIG = 9.194E0_r4
372 real(rk), parameter :: XHUGE = 2.90E3_r4
373 real(rk), parameter :: XMAX = 4.79E37_r4
375 !------------------------------------------------------------------
376 ! Coefficients for approximation to erf in first interval
377 !------------------------------------------------------------------
378 real(rk), parameter :: A(5) = (/ 3.16112374387056560E00_rk, 1.13864154151050156E02_rk, &
379 3.77485237685302021E02_rk, 3.20937758913846947E03_rk, &
380 1.85777706184603153E-1_rk /)
381 real(rk), parameter :: B(4) = (/ 2.36012909523441209E01_rk, 2.44024637934444173E02_rk, &
382 1.28261652607737228E03_rk, 2.84423683343917062E03_rk /)
384 !------------------------------------------------------------------
385 ! Coefficients for approximation to erfc in second interval
386 !------------------------------------------------------------------
387 real(rk), parameter :: C(9) = (/ 5.64188496988670089E-1_rk, 8.88314979438837594E00_rk, &
388 6.61191906371416295E01_rk, 2.98635138197400131E02_rk, &
389 8.81952221241769090E02_rk, 1.71204761263407058E03_rk, &
390 2.05107837782607147E03_rk, 1.23033935479799725E03_rk, &
391 2.15311535474403846E-8_rk /)
392 real(rk), parameter :: D(8) = (/ 1.57449261107098347E01_rk, 1.17693950891312499E02_rk, &
393 5.37181101862009858E02_rk, 1.62138957456669019E03_rk, &
394 3.29079923573345963E03_rk, 4.36261909014324716E03_rk, &
395 3.43936767414372164E03_rk, 1.23033935480374942E03_rk /)
397 !------------------------------------------------------------------
398 ! Coefficients for approximation to erfc in third interval
399 !------------------------------------------------------------------
400 real(rk), parameter :: P(6) = (/ 3.05326634961232344E-1_rk, 3.60344899949804439E-1_rk, &
401 1.25781726111229246E-1_rk, 1.60837851487422766E-2_rk, &
402 6.58749161529837803E-4_rk, 1.63153871373020978E-2_rk /)
403 real(rk), parameter :: Q(5) = (/ 2.56852019228982242E00_rk, 1.87295284992346047E00_rk, &
404 5.27905102951428412E-1_rk, 6.05183413124413191E-2_rk, &
405 2.33520497626869185E-3_rk /)
407 !------------------------------------------------------------------
410 IF (Y .LE. THRESH) THEN
411 !------------------------------------------------------------------
412 ! Evaluate erf for |X| <= 0.46875
413 !------------------------------------------------------------------
415 IF (Y .GT. XSMALL) YSQ = Y * Y
419 XNUM = (XNUM + A(I)) * YSQ
420 XDEN = (XDEN + B(I)) * YSQ
422 RESULT = X * (XNUM + A(4)) / (XDEN + B(4))
423 IF (JINT .NE. 0) RESULT = ONE - RESULT
424 IF (JINT .EQ. 2) RESULT = EXP(YSQ) * RESULT
426 ELSE IF (Y .LE. FOUR) THEN
427 !------------------------------------------------------------------
428 ! Evaluate erfc for 0.46875 <= |X| <= 4.0
429 !------------------------------------------------------------------
433 XNUM = (XNUM + C(I)) * Y
434 XDEN = (XDEN + D(I)) * Y
436 RESULT = (XNUM + C(8)) / (XDEN + D(8))
437 IF (JINT .NE. 2) THEN
438 YSQ = AINT(Y*SIXTEN)/SIXTEN
439 DEL = (Y-YSQ)*(Y+YSQ)
440 RESULT = EXP(-YSQ*YSQ) * EXP(-DEL) * RESULT
443 !------------------------------------------------------------------
444 ! Evaluate erfc for |X| > 4.0
445 !------------------------------------------------------------------
447 IF (Y .GE. XBIG) THEN
448 IF ((JINT .NE. 2) .OR. (Y .GE. XMAX)) GO TO 30
449 IF (Y .GE. XHUGE) THEN
458 XNUM = (XNUM + P(I)) * YSQ
459 XDEN = (XDEN + Q(I)) * YSQ
461 RESULT = YSQ *(XNUM + P(5)) / (XDEN + Q(5))
462 RESULT = (SQRPI - RESULT) / Y
463 IF (JINT .NE. 2) THEN
464 YSQ = AINT(Y*SIXTEN)/SIXTEN
465 DEL = (Y-YSQ)*(Y+YSQ)
466 RESULT = EXP(-YSQ*YSQ) * EXP(-DEL) * RESULT
470 !------------------------------------------------------------------
471 ! Fix up for negative argument, erf, etc.
472 !------------------------------------------------------------------
473 IF (JINT .EQ. 0) THEN
474 RESULT = (HALF - RESULT) + HALF
475 IF (X .LT. ZERO) RESULT = -RESULT
476 ELSE IF (JINT .EQ. 1) THEN
477 IF (X .LT. ZERO) RESULT = TWO - RESULT
479 IF (X .LT. ZERO) THEN
480 IF (X .LT. XNEG) THEN
483 YSQ = AINT(X*SIXTEN)/SIXTEN
484 DEL = (X-YSQ)*(X+YSQ)
485 Y = EXP(YSQ*YSQ) * EXP(DEL)
486 RESULT = (Y+Y) - RESULT
491 end SUBROUTINE CALERF_r4
493 !------------------------------------------------------------------------------------------
496 !--------------------------------------------------------------------
498 ! This subprogram computes approximate values for erf(x).
499 ! (see comments heading CALERF).
501 ! Author/date: W. J. Cody, January 8, 1985
503 !--------------------------------------------------------------------
504 integer, parameter :: rk = r8 ! 8 byte real
507 real(rk), intent(in) :: X
514 !------------------------------------------------------------------
516 CALL CALERF_r8(X, DERF, JINT)
519 !------------------------------------------------------------------------------------------
522 !--------------------------------------------------------------------
524 ! This subprogram computes approximate values for erf(x).
525 ! (see comments heading CALERF).
527 ! Author/date: W. J. Cody, January 8, 1985
529 !--------------------------------------------------------------------
530 integer, parameter :: rk = r4 ! 4 byte real
533 real(rk), intent(in) :: X
540 !------------------------------------------------------------------
542 CALL CALERF_r4(X, ERF_r4, JINT)
545 !------------------------------------------------------------------------------------------
548 !--------------------------------------------------------------------
550 ! This subprogram computes approximate values for erfc(x).
551 ! (see comments heading CALERF).
553 ! Author/date: W. J. Cody, January 8, 1985
555 !--------------------------------------------------------------------
556 integer, parameter :: rk = r8 ! 8 byte real
559 real(rk), intent(in) :: X
566 !------------------------------------------------------------------
568 CALL CALERF_r8(X, DERFC, JINT)
571 !------------------------------------------------------------------------------------------
574 !--------------------------------------------------------------------
576 ! This subprogram computes approximate values for erfc(x).
577 ! (see comments heading CALERF).
579 ! Author/date: W. J. Cody, January 8, 1985
581 !--------------------------------------------------------------------
582 integer, parameter :: rk = r4 ! 4 byte real
585 real(rk), intent(in) :: X
592 !------------------------------------------------------------------
594 CALL CALERF_r4(X, ERFC_r4, JINT)
597 !------------------------------------------------------------------------------------------
600 !--------------------------------------------------------------------
602 ! This subprogram computes approximate values for exp(x*x) * erfc(x).
603 ! (see comments heading CALERF).
605 ! Author/date: W. J. Cody, March 30, 1987
607 !--------------------------------------------------------------------
608 integer, parameter :: rk = r8 ! 8 byte real
611 real(rk), intent(in) :: X
618 !------------------------------------------------------------------
620 CALL CALERF_r8(X, DERFCX, JINT)
623 !------------------------------------------------------------------------------------------
626 !--------------------------------------------------------------------
628 ! This subprogram computes approximate values for exp(x*x) * erfc(x).
629 ! (see comments heading CALERF).
631 ! Author/date: W. J. Cody, March 30, 1987
633 !--------------------------------------------------------------------
634 integer, parameter :: rk = r4 ! 8 byte real
637 real(rk), intent(in) :: X
644 !------------------------------------------------------------------
646 CALL CALERF_r4(X, ERFCX_R4, JINT)
647 END FUNCTION ERFCX_R4
649 !------------------------------------------------------------------------------------------
651 end module error_function