STK++ 1.0
STK_Law_Normal.cpp
Go to the documentation of this file.
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