!==================================================================================! ! Series of subroutines and functions to handle probability distributions ! downloaded from: ! !http://people.sc.fsu.edu/~jburkardt/f_src/prob/prob.f90 ! !==================================================================================! module handle_prob_distr contains function error_f ( x ) !*****************************************************************************80 ! !! ERROR_F evaluates the error function ERF. ! ! Discussion: ! ! Since some compilers already supply a routine named ERF which evaluates ! the error function, this routine has been given a distinct, if ! somewhat unnatural, name. ! ! The function is defined by: ! ! ERF(X) = ( 2 / sqrt ( PI ) ) * Integral ( 0 <= T <= X ) EXP ( - T^2 ) dT. ! ! Properties of the function include: ! ! Limit ( X -> -Infinity ) ERF(X) = -1.0; ! ERF(0) = 0.0; ! ERF(0.476936...) = 0.5; ! Limit ( X -> +Infinity ) ERF(X) = +1.0. ! ! 0.5D+00 * ( ERF(X/sqrt(2)) + 1 ) = Normal_01_CDF(X) ! ! Licensing: ! ! This code is distributed under the GNU LGPL license. ! ! Modified: ! ! 17 November 2006 ! ! Author: ! ! Original FORTRAN77 version by William Cody. ! FORTRAN90 version by John Burkardt. ! ! Reference: ! ! William Cody, ! Rational Chebyshev Approximations for the Error Function, ! Mathematics of Computation, ! 1969, pages 631-638. ! ! Parameters: ! ! Input, real ( kind = 8 ) X, the argument of the error function. ! ! Output, real ( kind = 8 ) ERROR_F, the value of the error function. ! implicit none real ( kind = 8 ), parameter, dimension ( 5 ) :: a = (/ & 3.16112374387056560D+00, & 1.13864154151050156D+02, & 3.77485237685302021D+02, & 3.20937758913846947D+03, & 1.85777706184603153D-01 /) real ( kind = 8 ), parameter, dimension ( 4 ) :: b = (/ & 2.36012909523441209D+01, & 2.44024637934444173D+02, & 1.28261652607737228D+03, & 2.84423683343917062D+03 /) real ( kind = 8 ), parameter, dimension ( 9 ) :: c = (/ & 5.64188496988670089D-01, & 8.88314979438837594D+00, & 6.61191906371416295D+01, & 2.98635138197400131D+02, & 8.81952221241769090D+02, & 1.71204761263407058D+03, & 2.05107837782607147D+03, & 1.23033935479799725D+03, & 2.15311535474403846D-08 /) real ( kind = 8 ), parameter, dimension ( 8 ) :: d = (/ & 1.57449261107098347D+01, & 1.17693950891312499D+02, & 5.37181101862009858D+02, & 1.62138957456669019D+03, & 3.29079923573345963D+03, & 4.36261909014324716D+03, & 3.43936767414372164D+03, & 1.23033935480374942D+03 /) real ( kind = 8 ) del real ( kind = 8 ) error_f integer ( kind = 4 ) i real ( kind = 8 ), parameter, dimension ( 6 ) :: p = (/ & 3.05326634961232344D-01, & 3.60344899949804439D-01, & 1.25781726111229246D-01, & 1.60837851487422766D-02, & 6.58749161529837803D-04, & 1.63153871373020978D-02 /) real ( kind = 8 ), parameter, dimension ( 5 ) :: q = (/ & 2.56852019228982242D+00, & 1.87295284992346047D+00, & 5.27905102951428412D-01, & 6.05183413124413191D-02, & 2.33520497626869185D-03 /) real ( kind = 8 ), parameter :: sqrpi = 0.56418958354775628695D+00 real ( kind = 8 ), parameter :: thresh = 0.46875D+00 real ( kind = 8 ) x real ( kind = 8 ) xabs real ( kind = 8 ), parameter :: xbig = 26.543D+00 real ( kind = 8 ) xden real ( kind = 8 ) xnum real ( kind = 8 ) xsq xabs = abs ( ( x ) ) ! ! Evaluate ERF(X) for |X| <= 0.46875. ! if ( xabs <= thresh ) then if ( epsilon ( xabs ) < xabs ) then xsq = xabs * xabs else xsq = 0.0D+00 end if xnum = a(5) * xsq xden = xsq do i = 1, 3 xnum = ( xnum + a(i) ) * xsq xden = ( xden + b(i) ) * xsq end do error_f = x * ( xnum + a(4) ) / ( xden + b(4) ) ! ! Evaluate ERFC(X) for 0.46875 <= |X| <= 4.0. ! else if ( xabs <= 4.0D+00 ) then xnum = c(9) * xabs xden = xabs do i = 1, 7 xnum = ( xnum + c(i) ) * xabs xden = ( xden + d(i) ) * xabs end do error_f = ( xnum + c(8) ) / ( xden + d(8) ) xsq = real ( int ( xabs * 16.0D+00 ), kind = 8 ) / 16.0D+00 del = ( xabs - xsq ) * ( xabs + xsq ) error_f = exp ( - xsq * xsq ) * exp ( - del ) * error_f error_f = ( 0.5D+00 - error_f ) + 0.5D+00 if ( x < 0.0D+00 ) then error_f = - error_f end if ! ! Evaluate ERFC(X) for 4.0D+00 < |X|. ! else if ( xbig <= xabs ) then if ( 0.0D+00 < x ) then error_f = 1.0D+00 else error_f = - 1.0D+00 end if else xsq = 1.0D+00 / ( xabs * xabs ) xnum = p(6) * xsq xden = xsq do i = 1, 4 xnum = ( xnum + p(i) ) * xsq xden = ( xden + q(i) ) * xsq end do error_f = xsq * ( xnum + p(5) ) / ( xden + q(5) ) error_f = ( sqrpi - error_f ) / xabs xsq = real ( int ( xabs * 16.0D+00 ), kind = 8 ) / 16.0D+00 del = ( xabs - xsq ) * ( xabs + xsq ) error_f = exp ( - xsq * xsq ) * exp ( - del ) * error_f error_f = ( 0.5D+00 - error_f ) + 0.5D+00 if ( x < 0.0D+00 ) then error_f = - error_f end if end if end if return end function !--------------------------------------------------------------------------------! function error_f_inverse ( y ) !*****************************************************************************80 ! !! ERROR_F_INVERSE inverts the error function ERF. ! ! Licensing: ! ! This code is distributed under the GNU LGPL license. ! ! Modified: ! ! 05 August 2010 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, real ( kind = 8 ) Y, the value of the error function. ! ! Output, real ( kind = 8 ) ERROR_F_INVERSE, the value X such that ! ERROR_F(X) = Y. ! implicit none real ( kind = 8 ) error_f_inverse real ( kind = 8 ) x real ( kind = 8 ) y real ( kind = 8 ) z z = ( y + 1.0D+00 ) / 2.0D+00 call normal_01_cdf_inv ( z, x ) error_f_inverse = x / sqrt ( 2.0D+00 ) return end function !--------------------------------------------------------------------------------! subroutine normal_01_cdf_inv ( p, x ) !*****************************************************************************80 ! !! NORMAL_01_CDF_INV inverts the standard normal CDF. ! ! Discussion: ! ! The result is accurate to about 1 part in 10^16. ! ! Licensing: ! ! This code is distributed under the GNU LGPL license. ! ! Modified: ! ! 05 June 2007 ! ! Author: ! ! Original FORTRAN77 version by Michael Wichura. ! FORTRAN90 version by John Burkardt. ! ! Reference: ! ! Michael Wichura, ! Algorithm AS241: ! The Percentage Points of the Normal Distribution, ! Applied Statistics, ! Volume 37, Number 3, pages 477-484, 1988. ! ! Parameters: ! ! Input, real ( kind = 8 ) P, the value of the cumulative probability ! densitity function. 0 < P < 1. If P is outside this range, an ! "infinite" value will be returned. ! ! Output, real ( kind = 8 ) X, the normal deviate value ! with the property that the probability of a standard normal deviate being ! less than or equal to the value is P. ! implicit none real ( kind = 8 ), parameter, dimension ( 8 ) :: a = (/ & 3.3871328727963666080D+00, & 1.3314166789178437745D+02, & 1.9715909503065514427D+03, & 1.3731693765509461125D+04, & 4.5921953931549871457D+04, & 6.7265770927008700853D+04, & 3.3430575583588128105D+04, & 2.5090809287301226727D+03 /) real ( kind = 8 ), parameter, dimension ( 8 ) :: b = (/ & 1.0D+00, & 4.2313330701600911252D+01, & 6.8718700749205790830D+02, & 5.3941960214247511077D+03, & 2.1213794301586595867D+04, & 3.9307895800092710610D+04, & 2.8729085735721942674D+04, & 5.2264952788528545610D+03 /) real ( kind = 8 ), parameter, dimension ( 8 ) :: c = (/ & 1.42343711074968357734D+00, & 4.63033784615654529590D+00, & 5.76949722146069140550D+00, & 3.64784832476320460504D+00, & 1.27045825245236838258D+00, & 2.41780725177450611770D-01, & 2.27238449892691845833D-02, & 7.74545014278341407640D-04 /) real ( kind = 8 ), parameter :: const1 = 0.180625D+00 real ( kind = 8 ), parameter :: const2 = 1.6D+00 real ( kind = 8 ), parameter, dimension ( 8 ) :: d = (/ & 1.0D+00, & 2.05319162663775882187D+00, & 1.67638483018380384940D+00, & 6.89767334985100004550D-01, & 1.48103976427480074590D-01, & 1.51986665636164571966D-02, & 5.47593808499534494600D-04, & 1.05075007164441684324D-09 /) real ( kind = 8 ), parameter, dimension ( 8 ) :: e = (/ & 6.65790464350110377720D+00, & 5.46378491116411436990D+00, & 1.78482653991729133580D+00, & 2.96560571828504891230D-01, & 2.65321895265761230930D-02, & 1.24266094738807843860D-03, & 2.71155556874348757815D-05, & 2.01033439929228813265D-07 /) real ( kind = 8 ), parameter, dimension ( 8 ) :: f = (/ & 1.0D+00, & 5.99832206555887937690D-01, & 1.36929880922735805310D-01, & 1.48753612908506148525D-02, & 7.86869131145613259100D-04, & 1.84631831751005468180D-05, & 1.42151175831644588870D-07, & 2.04426310338993978564D-15 /) real ( kind = 8 ) p real ( kind = 8 ) q real ( kind = 8 ) r real ( kind = 8 ) r8poly_value real ( kind = 8 ), parameter :: split1 = 0.425D+00 real ( kind = 8 ), parameter :: split2 = 5.0D+00 real ( kind = 8 ) x if ( p <= 0.0D+00 ) then x = - huge ( x ) return end if if ( 1.0D+00 <= p ) then x = huge ( x ) return end if q = p - 0.5D+00 if ( abs ( q ) <= split1 ) then r = const1 - q * q x = q * r8poly_value ( 8, a, r ) / r8poly_value ( 8, b, r ) else if ( q < 0.0D+00 ) then r = p else r = 1.0D+00 - p end if if ( r <= 0.0D+00 ) then x = huge ( x ) else r = sqrt ( - log ( r ) ) if ( r <= split2 ) then r = r - const2 x = r8poly_value ( 8, c, r ) / r8poly_value ( 8, d, r ) else r = r - split2 x = r8poly_value ( 8, e, r ) / r8poly_value ( 8, f, r ) end if end if if ( q < 0.0D+00 ) then x = -x end if end if return end subroutine end module handle_prob_distr !==================================================================================!