/home/coin/SVN-release/CoinAll-1.1.0/cppad/cppad/local/erf.hpp

Go to the documentation of this file.
00001 # ifndef CPPAD_ERF_INCLUDED
00002 # define CPPAD_ERF_INCLUDED
00003 
00004 /* --------------------------------------------------------------------------
00005 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-07 Bradley M. Bell
00006 
00007 CppAD is distributed under multiple licenses. This distribution is under
00008 the terms of the 
00009                     Common Public License Version 1.0.
00010 
00011 A copy of this license is included in the COPYING file of this distribution.
00012 Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
00013 -------------------------------------------------------------------------- */
00014 
00015 /*
00016 -------------------------------------------------------------------------------
00017 $begin erf$$
00018 
00019 $section The AD Error Function$$
00020 $spell
00021         Cpp
00022         namespace
00023         Vec
00024         erf
00025         const
00026 $$
00027 
00028 $index erf, AD function$$
00029 $index error, AD function$$
00030 $index function, AD error$$
00031 
00032 $head Syntax$$
00033 $syntax%%y% = erf(%x%)%$$
00034 
00035 
00036 $head Description$$
00037 Returns the value of the error function which is defined by
00038 $latex \[
00039 {\rm erf} (x) = \frac{2}{ \sqrt{\pi} } \int_0^x \exp( - t * t ) \; {\bf d} t
00040 \] $$
00041 
00042 $head Base$$ 
00043 A definition of $code erf$$ for arguments of type
00044 $code float$$ and $code double$$ 
00045 is included in the $code CppAD$$ namespace
00046 (the corresponding results has the same type as the arguments).
00047 The type $italic Base$$ can be any type in the 
00048 $cref/AD levels above/glossary/AD Levels Above Base/$$
00049 above $code float$$ or $code double$$.
00050 
00051 $head x$$
00052 The argument $italic x$$ has prototype
00053 $syntax%
00054         const AD<%Base%>               &%x%
00055         const VecAD<%Base%>::reference &%x%
00056 %$$
00057 
00058 $head y$$
00059 The result $italic y$$ has prototype
00060 $syntax%
00061         AD<%Base%> %y%
00062 %$$
00063 
00064 $head Operation Sequence$$
00065 The AD of $italic Base$$
00066 operation sequence used to calculate $italic y$$ is
00067 $xref/glossary/Operation/Independent/independent/1/$$
00068 of $italic x$$.
00069 
00070 $head Example$$
00071 $children%
00072         example/erf.cpp
00073 %$$
00074 The file
00075 $xref/Erf.cpp/$$
00076 contains an example and test of this function.   
00077 It returns true if it succeeds and false otherwise.
00078 
00079 $end
00080 -------------------------------------------------------------------------------
00081 */
00082 
00083 /*
00084  * ====================================================
00085  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
00086  *
00087  * Developed at SunSoft, a Sun Microsystems, Inc. business.
00088  * Permission to use, copy, modify, and distribute this
00089  * software is freely granted, provided that this notice 
00090  * is preserved.
00091  * ====================================================
00092  *
00093  *
00094  * double erf(double x)
00095  * double erfc(double x)
00096  *                           x
00097  *                    2      |\
00098  *     erf(x)  =  ---------  | exp(-t*t)dt
00099  *                 sqrt(pi) \| 
00100  *                           0
00101  *
00102  *     erfc(x) =  1-erf(x)
00103  *  Note that 
00104  *              erf(-x) = -erf(x)
00105  *              erfc(-x) = 2 - erfc(x)
00106  *
00107  * Method:
00108  *      1. For |x| in [0, 0.84375]
00109  *          erf(x)  = x + x*R(x^2)
00110  *          erfc(x) = 1 - erf(x)           if x in [-.84375,0.25]
00111  *                  = 0.5 + ((0.5-x)-x*R)  if x in [0.25,0.84375]
00112  *         where R = P/Q where P is an odd poly of degree 8 and
00113  *         Q is an odd poly of degree 10.
00114  *                                               -57.90
00115  *                      | R - (erf(x)-x)/x | <= 2
00116  *      
00117  *
00118  *         Remark. The formula is derived by noting
00119  *          erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....)
00120  *         and that
00121  *          2/sqrt(pi) = 1.128379167095512573896158903121545171688
00122  *         is close to one. The interval is chosen because the fix
00123  *         point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is
00124  *         near 0.6174), and by some experiment, 0.84375 is chosen to
00125  *         guarantee the error is less than one ulp for erf.
00126  *
00127  *      2. For |x| in [0.84375,1.25], let s = |x| - 1, and
00128  *         c = 0.84506291151 rounded to single (24 bits)
00129  *              erf(x)  = sign(x) * (c  + P1(s)/Q1(s))
00130  *              erfc(x) = (1-c)  - P1(s)/Q1(s) if x > 0
00131  *                        1+(c+P1(s)/Q1(s))    if x < 0
00132  *              |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06
00133  *         Remark: here we use the taylor series expansion at x=1.
00134  *              erf(1+s) = erf(1) + s*Poly(s)
00135  *                       = 0.845.. + P1(s)/Q1(s)
00136  *         That is, we use rational approximation to approximate
00137  *                      erf(1+s) - (c = (single)0.84506291151)
00138  *         Note that |P1/Q1|< 0.078 for x in [0.84375,1.25]
00139  *         where 
00140  *              P1(s) = degree 6 poly in s
00141  *              Q1(s) = degree 6 poly in s
00142  *
00143  *      3. For x in [1.25,1/0.35(~2.857143)], 
00144  *              erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1)
00145  *              erf(x)  = 1 - erfc(x)
00146  *         where 
00147  *              R1(z) = degree 7 poly in z, (z=1/x^2)
00148  *              S1(z) = degree 8 poly in z
00149  *
00150  *      4. For x in [1/0.35,28]
00151  *              erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0
00152  *                      = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6<x<0
00153  *                      = 2.0 - tiny            (if x <= -6)
00154  *              erf(x)  = sign(x)*(1.0 - erfc(x)) if x < 6, else
00155  *              erf(x)  = sign(x)*(1.0 - tiny)
00156  *         where
00157  *              R2(z) = degree 6 poly in z, (z=1/x^2)
00158  *              S2(z) = degree 7 poly in z
00159  *
00160  *      Note1:
00161  *         To compute exp(-x*x-0.5625+R/S), let s be a single
00162  *         precision number and s := x; then
00163  *              -x*x = -s*s + (s-x)*(s+x)
00164  *              exp(-x*x-0.5626+R/S) = 
00165  *                      exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S);
00166  *      Note2:
00167  *         Here 4 and 5 make use of the asymptotic series
00168  *                        exp(-x*x)
00169  *              erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) )
00170  *                        x*sqrt(pi)
00171  *         We use rational approximation to approximate
00172  *              g(s)=f(1/x^2) = log(erfc(x)*x) - x*x + 0.5625
00173  *         Here is the error bound for R1/S1 and R2/S2
00174  *              |R1/S1 - f(x)|  < 2**(-62.57)
00175  *              |R2/S2 - f(x)|  < 2**(-61.52)
00176  *
00177  *      5. For inf > x >= 28
00178  *              erf(x)  = sign(x) *(1 - tiny)  (raise inexact)
00179  *              erfc(x) = tiny*tiny (raise underflow) if x > 0
00180  *                      = 2 - tiny if x<0
00181  *
00182  *      7. Special case:
00183  *              erf(0)  = 0, erf(inf)  = 1, erf(-inf) = -1,
00184  *              erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, 
00185  *              erfc/erf(NaN) is NaN
00186  */
00187 
00188 
00189 # include <cmath>
00190 # include <cppad/cppad.hpp>
00191 
00192 // BEGIN CppAD namespace
00193 namespace CppAD {   
00194 
00195 template <class Type>
00196 Type erf_template(const Type &x)
00197 {       using CppAD::exp;
00198 
00199         static const Type
00200                 tiny = static_cast<Type>(  1e-300                     ),
00201                 one  = static_cast<Type>(  1.00000000000000000000e+00 ),
00202                         
00203                 erx  = static_cast<Type>(  8.45062911510467529297e-01 ),
00204                 /*
00205                  * Coefficients for approximation to  erf on [0,0.84375]
00206                  */
00207                 pp0  = static_cast<Type>(  1.28379167095512558561e-01 ),
00208                 pp1  = static_cast<Type>( -3.25042107247001499370e-01 ),
00209                 pp2  = static_cast<Type>( -2.84817495755985104766e-02 ),
00210                 pp3  = static_cast<Type>( -5.77027029648944159157e-03 ),
00211                 pp4  = static_cast<Type>( -2.37630166566501626084e-05 ),
00212                 qq1  = static_cast<Type>(  3.97917223959155352819e-01 ),
00213                 qq2  = static_cast<Type>(  6.50222499887672944485e-02 ),
00214                 qq3  = static_cast<Type>(  5.08130628187576562776e-03 ),
00215                 qq4  = static_cast<Type>(  1.32494738004321644526e-04 ),
00216                 qq5  = static_cast<Type>( -3.96022827877536812320e-06 ),
00217                 /*
00218                  * Coefficients for approximation to  erf  in [0.84375,1.25] 
00219                  */
00220                 pa0  = static_cast<Type>( -2.36211856075265944077e-03 ),
00221                 pa1  = static_cast<Type>(  4.14856118683748331666e-01 ),
00222                 pa2  = static_cast<Type>( -3.72207876035701323847e-01 ),
00223                 pa3  = static_cast<Type>(  3.18346619901161753674e-01 ),
00224                 pa4  = static_cast<Type>( -1.10894694282396677476e-01 ),
00225                 pa5  = static_cast<Type>(  3.54783043256182359371e-02 ),
00226                 pa6  = static_cast<Type>( -2.16637559486879084300e-03 ),
00227                 qa1  = static_cast<Type>(  1.06420880400844228286e-01 ),
00228                 qa2  = static_cast<Type>(  5.40397917702171048937e-01 ),
00229                 qa3  = static_cast<Type>(  7.18286544141962662868e-02 ),
00230                 qa4  = static_cast<Type>(  1.26171219808761642112e-01 ),
00231                 qa5  = static_cast<Type>(  1.36370839120290507362e-02 ),
00232                 qa6  = static_cast<Type>(  1.19844998467991074170e-02 ),
00233                 /*
00234                  * Coefficients for approximation to  erfc in [1.25,1/0.35]
00235                  */
00236                 ra0  = static_cast<Type>( -9.86494403484714822705e-03 ),
00237                 ra1  = static_cast<Type>( -6.93858572707181764372e-01 ),
00238                 ra2  = static_cast<Type>( -1.05586262253232909814e+01 ),
00239                 ra3  = static_cast<Type>( -6.23753324503260060396e+01 ),
00240                 ra4  = static_cast<Type>( -1.62396669462573470355e+02 ),
00241                 ra5  = static_cast<Type>( -1.84605092906711035994e+02 ),
00242                 ra6  = static_cast<Type>( -8.12874355063065934246e+01 ),
00243                 ra7  = static_cast<Type>( -9.81432934416914548592e+00 ),
00244                 sa1  = static_cast<Type>(  1.96512716674392571292e+01 ),
00245                 sa2  = static_cast<Type>(  1.37657754143519042600e+02 ),
00246                 sa3  = static_cast<Type>(  4.34565877475229228821e+02 ),
00247                 sa4  = static_cast<Type>(  6.45387271733267880336e+02 ),
00248                 sa5  = static_cast<Type>(  4.29008140027567833386e+02 ),
00249                 sa6  = static_cast<Type>(  1.08635005541779435134e+02 ),
00250                 sa7  = static_cast<Type>(  6.57024977031928170135e+00 ),
00251                 sa8  = static_cast<Type>( -6.04244152148580987438e-02 ),
00252                 /*
00253                  * Coefficients for approximation to  erfc in [1/.35,28]
00254                  */
00255                 rb0  = static_cast<Type>( -9.86494292470009928597e-03 ),
00256                 rb1  = static_cast<Type>( -7.99283237680523006574e-01 ),
00257                 rb2  = static_cast<Type>( -1.77579549177547519889e+01 ),
00258                 rb3  = static_cast<Type>( -1.60636384855821916062e+02 ),
00259                 rb4  = static_cast<Type>( -6.37566443368389627722e+02 ),
00260                 rb5  = static_cast<Type>( -1.02509513161107724954e+03 ),
00261                 rb6  = static_cast<Type>( -4.83519191608651397019e+02 ),
00262                 sb1  = static_cast<Type>(  3.03380607434824582924e+01 ),
00263                 sb2  = static_cast<Type>(  3.25792512996573918826e+02 ),
00264                 sb3  = static_cast<Type>(  1.53672958608443695994e+03 ),
00265                 sb4  = static_cast<Type>(  3.19985821950859553908e+03 ),
00266                 sb5  = static_cast<Type>(  2.55305040643316442583e+03 ),
00267                 sb6  = static_cast<Type>(  4.74528541206955367215e+02 ),
00268                 sb7  = static_cast<Type>( -2.24409524465858183362e+01 );
00269 
00270         Type R,S,P,Q,s,y,z,r;
00271 
00272         Type ax, value;
00273 
00274         Type zero(0);
00275 
00276         // |x|
00277         ax = CondExpGe(x, zero, x, -x);
00278 
00279         // erf(|x|) when |x| <= 0.84375
00280         z = ax*ax;
00281         r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
00282         s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
00283         y = r/s;
00284         Type Le0Dot84375 = ax + ax*y;
00285 
00286         // erf(|x|) when 0.84375 < |x| <= 1.25 
00287         s = ax-one;
00288         P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
00289         Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
00290         value = erx + P/Q; 
00291 
00292         // erf(|x|) when |x| <= 1.25
00293         Type Le1Dot25 = CondExpGt(ax, Type(0.84375), value, Le0Dot84375);
00294 
00295         // erf(|x|) when 1.25 < |x| <= 1 / 0.35
00296         s = one/(ax*ax);
00297         R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
00298                 ra5+s*(ra6+s*ra7))))));
00299         S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
00300                 sa5+s*(sa6+s*(sa7+s*sa8)))))));
00301         r  =  exp(Type(-0.5625)) * exp(-ax*ax+R/S);
00302         value = one-r/ax;
00303 
00304         // erf(|x|) when |x| <= 1 / 0.35
00305         Type Le1OverDot35 = CondExpGt(ax, Type(1.25), value, Le1Dot25);
00306 
00307         // erf(|x|) when 1 / 0.35 < |x| <= 6
00308         R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
00309                 rb5+s*rb6)))));
00310         S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
00311                 sb5+s*(sb6+s*sb7))))));
00312         r  =  exp(Type(-0.5625)) * exp(-ax*ax+R/S);
00313         value = one-r/ax;
00314 
00315         // erf(|x|) when |x| <= 6
00316         Type Le6 = CondExpGt(ax, Type(1/.35), value, Le1OverDot35); 
00317 
00318         // erf(|x|) when |x| > 6
00319         Type Gt6 = one - tiny;
00320 
00321         // erf(|x|) 
00322         Type Gt0 = CondExpGt(ax, Type(6.), Gt6, Le6);
00323 
00324         // Gt0 = erf( CondExpGe(x, zero, x, -x) )
00325         // so must switch sign in case where x < 0
00326         return CondExpGe(x, zero, Gt0, -Gt0);
00327 }
00328 
00329 inline float erf(const float &x)
00330 {       return erf_template(x); }
00331 
00332 inline double erf(const double &x)
00333 {       return erf_template(x); }
00334 
00335 template <class Base>
00336 inline AD<Base> erf(const AD<Base> &x)
00337 {       return erf_template(x); }
00338 
00339 template <class Base>
00340 inline AD<Base> erf(const VecAD_reference<Base> &x)
00341 {       return erf_template( x.ADBase() ); }
00342 
00343 
00344 } // END CppAD namespace
00345 
00346 # endif

Generated on Sun Nov 14 14:06:33 2010 for Coin-All by  doxygen 1.4.7