|
STK++ 1.0
|
00001 /*--------------------------------------------------------------------*/ 00002 /* Copyright (C) 2004-2008 Serge Iovleff 00003 00004 This program is free software; you can redistribute it and/or modify 00005 it under the terms of the GNU Lesser General Public License as 00006 published by the Free Software Foundation; either version 2 of the 00007 License, or (at your option) any later version. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU Lesser General Public License for more details. 00013 00014 You should have received a copy of the GNU Lesser General Public 00015 License along with this program; if not, write to the 00016 Free Software Foundation, Inc., 00017 59 Temple Place, 00018 Suite 330, 00019 Boston, MA 02111-1307 00020 USA 00021 00022 Contact : Serge.Iovleff@stkpp.org 00023 */ 00024 00025 /* 00026 * Project: STatistik 00027 * Purpose: implementation of the Normal Distribution 00028 * Author: Serge Iovleff, serge.iovleff@stkpp.org 00029 **/ 00030 00035 #include "../include/STK_Law_Normal.h" 00036 00037 namespace STK 00038 { 00039 00040 namespace Law 00041 { 00042 /* constructor */ 00043 Normal::Normal(Real const& mu, Real const& sigma) 00044 : ITUnivariate<Real>(String(_T("Normal"))) 00045 , mu_(mu) 00046 , sigma_(sigma) 00047 { 00048 // check parameters 00049 if ( !Arithmetic<Real>::isFinite(mu) 00050 || !Arithmetic<Real>::isFinite(sigma) 00051 || sigma < 0 00052 ) 00053 throw domain_error("Normal::Normal(mu, sigma) argument error"); 00054 } 00055 00056 /* destructor */ 00057 Normal::~Normal() 00058 { ;} 00059 00060 /* 00061 * Generate a pseudo Normal random variate. 00062 */ 00063 Real Normal::rand() const 00064 { 00065 if (sigma_ == 0.) return mu_; 00066 else return generator.randGauss(mu_, sigma_); 00067 } 00068 00069 /* 00070 * Generate a pseudo Normal random variate with the specified parameters. 00071 * (static) 00072 */ 00073 Real Normal::rand(Real const& mu, Real const& sigma) 00074 { 00075 // check parameters 00076 if ( !Arithmetic<Real>::isFinite(mu) 00077 || !Arithmetic<Real>::isFinite(sigma) 00078 || sigma < 0 00079 ) 00080 throw domain_error("Normal::rand(mu, sigma) " 00081 "argument error"); 00082 // return variate 00083 if (sigma == 0.) return mu; 00084 else return mu + sigma * generator.randGauss(); 00085 } 00086 00087 /* 00088 * Give the value of the pdf at x. 00089 */ 00090 Real Normal::pdf(Real const& x) const 00091 { 00092 // check parameter 00093 if ( !Arithmetic<Real>::isFinite(x)) 00094 throw domain_error("Normal::pdf(x) argument error"); 00095 // trivial case 00096 if (sigma_ == 0.) 00097 return (x==mu_) ? 1. : 0.; 00098 // compute pdf 00099 const Real y = (x - mu_)/sigma_; 00100 return Const::_1_SQRT2PI_ * exp(-0.5 * y * y) / sigma_; 00101 } 00102 00103 /* 00104 * Give the value of the pdf at x. 00105 */ 00106 Real Normal::pdf(Real const& x, Real const& mu, Real const& sigma) 00107 { 00108 // check parameter 00109 if ( !Arithmetic<Real>::isFinite(x)) 00110 throw domain_error("Normal::pdf(x, mu, sigma) argument error"); 00111 // trivial case 00112 if (sigma == 0.) 00113 return (x==mu) ? 1. : 0.; 00114 // compute pdf 00115 const Real y = (x - mu)/sigma; 00116 return Const::_1_SQRT2PI_ * exp(-0.5 * y * y) / sigma; 00117 } 00118 00119 /* 00120 * Give the value of the log-pdf at x. 00121 */ 00122 Real Normal::lpdf(Real const& x) const 00123 { 00124 // check parameter 00125 if ( !Arithmetic<Real>::isFinite(x)) 00126 throw domain_error("Normal::lpdf(x) argument error"); 00127 // trivial case 00128 if (sigma_ == 0) 00129 return (x==mu_) ? 0. : -Arithmetic<Real>::infinity(); 00130 // compute lpdf 00131 const Real y = (x - mu_)/sigma_; 00132 return -(Const::_LNSQRT2PI_ + log(sigma_) + 0.5 * y * y); 00133 } 00134 00135 /* 00136 * The cumulative distribution function at t. 00137 */ 00138 Real Normal::cdf(Real const& t) const 00139 { 00140 // check parameter 00141 if ( !Arithmetic<Real>::isFinite(t)) 00142 throw domain_error("Normal::cdf(t) argument error"); 00143 // coefficients 00144 const Real a[5] = 00145 { 00146 1.161110663653770e-002 00147 , 3.951404679838207e-001 00148 , 2.846603853776254e+001 00149 , 1.887426188426510e+002 00150 , 3.209377589138469e+003 00151 }; 00152 const Real b[5] = 00153 { 00154 1.767766952966369e-001 00155 , 8.344316438579620e+000 00156 , 1.725514762600375e+002 00157 , 1.813893686502485e+003 00158 , 8.044716608901563e+003 00159 }; 00160 const Real c[9] = 00161 { 00162 2.15311535474403846e-8 00163 , 5.64188496988670089e-1 00164 , 8.88314979438837594e00 00165 , 6.61191906371416295e01 00166 , 2.98635138197400131e02 00167 , 8.81952221241769090e02 00168 , 1.71204761263407058e03 00169 , 2.05107837782607147e03 00170 , 1.23033935479799725E03 00171 }; 00172 const Real d[9] = 00173 { 00174 1.00000000000000000e00 00175 , 1.57449261107098347e01 00176 , 1.17693950891312499e02 00177 , 5.37181101862009858e02 00178 , 1.62138957456669019e03 00179 , 3.29079923573345963e03 00180 , 4.36261909014324716e03 00181 , 3.43936767414372164e03 00182 , 1.23033935480374942e03 00183 }; 00184 const Real p[6] = 00185 { 00186 1.63153871373020978e-2 00187 , 3.05326634961232344e-1 00188 , 3.60344899949804439e-1 00189 , 1.25781726111229246e-1 00190 , 1.60837851487422766e-2 00191 , 6.58749161529837803e-4 00192 }; 00193 const Real q[6] = 00194 { 00195 1.00000000000000000e00 00196 , 2.56852019228982242e00 00197 , 1.87295284992346047e00 00198 , 5.27905102951428412e-1 00199 , 6.05183413124413191e-2 00200 , 2.33520497626869185e-3 00201 }; 00202 // trivial case 00203 if (sigma_ == 0) 00204 return (t < mu_) ? 0. : 1.; 00205 // change of variable 00206 Real y = abs((t - mu_) / sigma_); 00207 // 00208 if (y <= 0.46875*Const::_SQRT2_) 00209 { 00210 // evaluate erf() for |y| <= sqrt(2)*0.46875 using expansion 00211 const Real z = y*y; 00212 return t * ((((a[0]*z+a[1])*z+a[2])*z+a[3])*z+a[4]) 00213 / ((((b[0]*z+b[1])*z+b[2])*z+b[3])*z+b[4]) 00214 + 0.5; 00215 } 00216 // 00217 Real z = exp(-y*y/2)/2; 00218 if (y <= 4.0) 00219 { 00220 /* evaluate erfc() for sqrt(2)*0.46875 <= |y| <= sqrt(2)*4.0 */ 00221 y /= Const::_SQRT2_; 00222 y = ((((((((c[0]*y+c[1])*y+c[2])*y+c[3])*y+c[4])*y+c[5])*y+c[6])*y+c[7])*y+c[8]) 00223 /((((((((d[0]*y+d[1])*y+d[2])*y+d[3])*y+d[4])*y+d[5])*y+d[6])*y+d[7])*y+d[8]); 00224 y *= z; 00225 } 00226 else 00227 { 00228 /* evaluate erfc() for |y| > sqrt(2)*4.0 */ 00229 z *= Const::_SQRT2_/y; 00230 y = 2/(y*y); 00231 y = y*(((((p[0]*y+p[1])*y+p[2])*y+p[3])*y+p[4])*y+p[5]) 00232 /(((((q[0]*y+q[1])*y+q[2])*y+q[3])*y+q[4])*y+q[5]); 00233 y = z*(Const::_1_SQRTPI_-y); 00234 } 00235 // lower or upper tail 00236 return (t < 0. ? y : 1.-y); 00237 } 00238 00239 /* 00240 * The inverse cumulative distribution function at p. 00241 */ 00242 Real Normal::icdf(Real const& p) const 00243 { 00244 // check parameter 00245 if ( !Arithmetic<Real>::isFinite(p) 00246 || p > 1. 00247 || p < 0. 00248 ) 00249 throw domain_error("Normal::icdf(p) argument error"); 00250 // trivial cases 00251 if (p == 0.) return -Arithmetic<Real>::infinity(); 00252 if (p == 1.) return Arithmetic<Real>::infinity(); 00253 if (p == 0.5) return mu_; 00254 00255 const Real a[6] = 00256 { 00257 -3.969683028665376e+01 00258 , 2.209460984245205e+02 00259 , -2.759285104469687e+02 00260 , 1.383577518672690e+02 00261 , -3.066479806614716e+01 00262 , 2.506628277459239e+00 00263 }; 00264 const Real b[5] = 00265 { 00266 -5.447609879822406e+01 00267 , 1.615858368580409e+02 00268 , -1.556989798598866e+02 00269 , 6.680131188771972e+01 00270 , -1.328068155288572e+01 00271 }; 00272 const Real c[6] = 00273 { 00274 -7.784894002430293e-03 00275 , -3.223964580411365e-01 00276 , -2.400758277161838e+00 00277 , -2.549732539343734e+00 00278 , 4.374664141464968e+00 00279 , 2.938163982698783e+00 00280 }; 00281 const Real d[4] = 00282 { 00283 7.784695709041462e-03 00284 , 3.224671290700398e-01 00285 , 2.445134137142996e+00 00286 , 3.754408661907416e+00 00287 }; 00288 00289 register Real t, u; 00290 00291 Real q = min(p, 1-p); 00292 if (q > 0.02425) 00293 { 00294 /* Rational approximation for central region. */ 00295 u = q-0.5; 00296 t = u*u; 00297 u = u*(((((a[0]*t+a[1])*t+a[2])*t+a[3])*t+a[4])*t+a[5]) 00298 /(((((b[0]*t+b[1])*t+b[2])*t+b[3])*t+b[4])*t+1.); 00299 } 00300 else 00301 { 00302 /* Rational approximation for tail region. */ 00303 t = sqrt(-2.*log(q)); 00304 u = (((((c[0]*t+c[1])*t+c[2])*t+c[3])*t+c[4])*t+c[5]) 00305 /((((d[0]*t+d[1])*t+d[2])*t+d[3])*t+1); 00306 } 00307 /* The relative error of the approximation has absolute value less 00308 than 1.15e-9. One iteration of Halley's rational method (third 00309 order) gives full machine precision... */ 00310 t = cdf(u)-q; /* error */ 00311 t = t*Const::_SQRT2PI_*exp(u*u/2); /* f(u)/df(u) */ 00312 u = u-t/(1+u*t/2); /* Halley's method */ 00313 00314 return (p > 0.5 ? mu_ - sigma_ * u : mu_ + sigma_ * u); 00315 } 00316 00317 } // namespace law 00318 00319 } // namespace STK