VavilovAccurate.cxx

Go to the documentation of this file.
00001 // @(#)root/mathmore:$Id: VavilovAccurate.cxx 34125 2010-06-25 08:30:28Z moneta $
00002 // Authors: B. List 29.4.2010
00003  
00004 
00005  /**********************************************************************
00006   *                                                                    *
00007   * Copyright (c) 2004 ROOT Foundation,  CERN/PH-SFT                   *
00008   *                                                                    *
00009   * This library is free software; you can redistribute it and/or      *
00010   * modify it under the terms of the GNU General Public License        *
00011   * as published by the Free Software Foundation; either version 2     *
00012   * of the License, or (at your option) any later version.             *
00013   *                                                                    *
00014   * This library is distributed in the hope that it will be useful,    *
00015   * but WITHOUT ANY WARRANTY; without even the implied warranty of     *
00016   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU   *
00017   * General Public License for more details.                           *
00018   *                                                                    *
00019   * You should have received a copy of the GNU General Public License  *
00020   * along with this library (see file COPYING); if not, write          *
00021   * to the Free Software Foundation, Inc., 59 Temple Place, Suite      *
00022   * 330, Boston, MA 02111-1307 USA, or contact the author.             *
00023   *                                                                    *
00024   **********************************************************************/
00025 
00026 // Implementation file for class VavilovAccurate
00027 // 
00028 // Created by: blist  at Thu Apr 29 11:19:00 2010
00029 // 
00030 // Last update: Thu Apr 29 11:19:00 2010
00031 // 
00032 
00033 
00034 #include "Math/VavilovAccurate.h"
00035 #include "Math/SpecFuncMathCore.h"
00036 #include "Math/SpecFuncMathMore.h"
00037 #include "Math/QuantFuncMathCore.h"
00038 
00039 #include <cassert>
00040 #include <iostream>
00041 #include <iomanip>
00042 #include <cmath>
00043 #include <limits>
00044 
00045 
00046 namespace ROOT {
00047 namespace Math {
00048 
00049 VavilovAccurate *VavilovAccurate::fgInstance = 0;
00050 
00051 
00052 VavilovAccurate::VavilovAccurate(double kappa, double beta2, double epsilonPM, double epsilon) 
00053 {
00054    Set (kappa, beta2, epsilonPM, epsilon);
00055 }
00056 
00057 
00058 VavilovAccurate::~VavilovAccurate() 
00059 {
00060    // desctructor (clean up resources)
00061 }
00062 
00063 void VavilovAccurate::SetKappaBeta2 (double kappa, double beta2) {
00064    Set (kappa, beta2);
00065 }
00066 
00067 void VavilovAccurate::Set(double kappa, double beta2, double epsilonPM, double epsilon) {
00068    // Method described in 
00069    // B. Schorr, Programs for the Landau and the Vavilov distributions and the corresponding random numbers, 
00070    // <A HREF="http://dx.doi.org/10.1016/0010-4655(74)90091-5">Computer Phys. Comm. 7 (1974) 215-224</A>. 
00071    fQuantileInit = false;
00072 
00073    fKappa = kappa;
00074    fBeta2 = beta2;
00075    fEpsilonPM = epsilonPM;    // epsilon_+ = epsilon_-: determines support (T0, T1) 
00076    fEpsilon = epsilon;
00077    
00078    static const double eu = 0.577215664901532860606;              // Euler's constant
00079    static const double pi2 = 6.28318530717958647693,              // 2pi
00080                        rpi = 0.318309886183790671538,             // 1/pi
00081                        pih = 1.57079632679489661923;              // pi/2
00082    double h1 = -std::log(fEpsilon)-1.59631259113885503887;        // -ln(fEpsilon) + ln(2/pi**2)
00083    double deltaEpsilon = 0.001;
00084    static const double logdeltaEpsilon = -std::log(deltaEpsilon); // 3 ln 10 = -ln(.001);
00085    double logEpsilonPM = std::log(fEpsilonPM); 
00086    static const double eps = 1e-5;                                // accuracy of root finding for x0
00087 
00088    double xp[9] = {0,
00089                    9.29,  2.47, 0.89, 0.36, 0.15, 0.07, 0.03, 0.02};
00090    double xq[7] = {0,
00091                    0.012, 0.03, 0.08, 0.26, 0.87, 3.83};
00092 
00093    if (kappa < 0.001) {
00094       std::cerr << "VavilovAccurate::Set: kappa = " << kappa << " - out of range" << std::endl;
00095       if (kappa < 0.001) kappa = 0.001;
00096    } 
00097    if (beta2 < 0 || beta2 > 1) {
00098       std::cerr << "VavilovAccurate::Set: beta2 = " << beta2 << " - out of range" << std::endl;
00099       if (beta2 < 0) beta2 = -beta2;
00100       if (beta2 > 1) beta2 = 1;
00101    }
00102    
00103    // approximation of x_-
00104    fH[5] = 1-beta2*(1-eu)-logEpsilonPM/kappa;       // eq. 3.9
00105    fH[6] = beta2;
00106    fH[7] = 1-beta2;
00107    double h4 = logEpsilonPM/kappa-(1+beta2*eu);
00108    double logKappa = std::log(kappa);
00109    double kappaInv = 1/kappa;
00110    // Calculate T0 from Eq. (3.6), using x_- = fH[5]
00111 //    double e1h5 = (fH[5] > 40 ) ? 0 : -ROOT::Math::expint (-fH[5]);
00112 //    fT0 = (h4-fH[5]*logKappa-(fH[5]+beta2)*(std::log(fH[5])+e1h5)+std::exp(-fH[5]))/fH[5];
00113    fT0 = (h4-fH[5]*logKappa-(fH[5]+beta2)*E1plLog(fH[5])+std::exp(-fH[5]))/fH[5];
00114    int lp = 1;
00115    while (lp < 9 && kappa < xp[lp]) ++lp;
00116    int lq = 1;
00117    while (lq < 7 && kappa >= xq[lq]) ++lq;
00118    // Solve eq. 3.7 to get fH[0] = x_+
00119    double delta = 0;
00120    int ifail = 0;
00121    do {
00122       ifail = Rzero(-lp-0.5-delta,lq-7.5+delta,fH[0],eps,1000,&ROOT::Math::VavilovAccurate::G116f2);
00123       delta += 0.5;
00124    } while (ifail == 2);   
00125    
00126    double q = 1/fH[0];
00127    // Calculate T1 from Eq. (3.6)
00128 //    double e1h0 = (fH[0] > 40 ) ? 0 : -ROOT::Math::expint (-fH[0]);
00129 //    fT1 = h4*q-logKappa-(1+beta2*q)*(std::log(std::fabs(fH[0]))+e1h0)+std::exp(-fH[0])*q;
00130    fT1 = h4*q-logKappa-(1+beta2*q)*E1plLog(fH[0])+std::exp(-fH[0])*q;
00131 
00132    fT = fT1-fT0;                         // Eq. (2.5)
00133    fOmega = pi2/fT;                      // Eq. (2.5)
00134    fH[1] = kappa*(2+beta2*eu)+h1;
00135    if(kappa >= 0.07) fH[1] += logdeltaEpsilon;       // reduce fEpsilon by a factor .001 for large kappa
00136    fH[2] = beta2*kappa;
00137    fH[3] = kappaInv*fOmega;
00138    fH[4] = pih*fOmega;
00139    
00140    // Solve log(eq. (4.10)) to get fX0 = N
00141    ifail = Rzero(5.,MAXTERMS,fX0,eps,1000,&ROOT::Math::VavilovAccurate::G116f1);
00142 //    if (ifail) {
00143 //       std::cerr << "Rzero failed for x0: ifail=" << ifail << ", kappa=" << kappa << ", beta2=" << beta2 << std::endl;
00144 //       std::cerr << "G116f1(" << 5. << ")=" << G116f1(5.) << ", G116f1(" << MAXTERMS << ")=" << G116f1(MAXTERMS)  << std::endl;
00145 //       std::cerr << "fH[0]=" << fH[0] << ", fH[1]=" << fH[1] << ", fH[2]=" << fH[2] << ", fH[3]=" << fH[3] << ", fH[4]=" << fH[4] << std::endl;
00146 //       std::cerr << "fH[5]=" << fH[5] << ", fH[6]=" << fH[6] << ", fH[7]=" << fH[7] << std::endl;
00147 //       std::cerr << "fT0=" << fT0 << ", fT1=" << fT1 << std::endl;
00148 //       std::cerr << "G116f2(" << fH[0] << ")=" << G116f2(fH[0]) << std::endl;
00149 //    }
00150    if (ifail == 2) {
00151       fX0 = (G116f1(5) > G116f1(MAXTERMS)) ? MAXTERMS : 5;
00152    }
00153    if (fX0 < 5) fX0 = 5;
00154    else if (fX0 > MAXTERMS) fX0 = MAXTERMS;
00155    int n = int(fX0+1);
00156    // logKappa=log(kappa)
00157    double d = rpi*std::exp(kappa*(1+beta2*(eu-logKappa)));
00158    fA_pdf[n] = rpi*fOmega;
00159    fA_cdf[n] = 0;
00160    q = -1;
00161    double q2 = 2;
00162    for (int k = 1; k < n; ++k) {
00163       int l = n-k;
00164       double x = fOmega*k;
00165       double x1 = kappaInv*x;
00166       double c1 = std::log(x)-ROOT::Math::cosint(x1);
00167       double c2 = ROOT::Math::sinint(x1);
00168       double c3 = std::sin(x1);
00169       double c4 = std::cos(x1);
00170       double xf1 = kappa*(beta2*c1-c4)-x*c2;
00171       double xf2 = x*(c1 + fT0) + kappa*(c3+beta2*c2);
00172       double d1 = q*d*fOmega*std::exp(xf1);
00173       double s = std::sin(xf2);
00174       double c = std::cos(xf2);
00175       fA_pdf[l] = d1*c;
00176       fB_pdf[l] = -d1*s;
00177       d1 = q*d*std::exp(xf1)/k;
00178       fA_cdf[l] = d1*s;
00179       fB_cdf[l] = d1*c;
00180       fA_cdf[n] += q2*fA_cdf[l];
00181       q = -q;
00182       q2 = -q2;
00183    }
00184 }
00185 
00186 void VavilovAccurate::InitQuantile() const {
00187    fQuantileInit = true;
00188 
00189    fNQuant = 16;
00190    // for kappa<0.02: use landau_quantile as first approximation
00191    if (fKappa < 0.02) return;
00192    else if (fKappa < 0.05) fNQuant = 32;
00193 
00194    // crude approximation for the median:
00195    
00196    double estmedian = -4.22784335098467134e-01-std::log(fKappa)-fBeta2;
00197    if (estmedian>1.3) estmedian = 1.3;
00198 
00199    // distribute test values evenly below and above the median
00200    for (int i = 1; i < fNQuant/2; ++i) {
00201       double x = fT0 + i*(estmedian-fT0)/(fNQuant/2);
00202       fQuant[i] = Cdf(x);
00203       fLambda[i] = x;
00204    }
00205    for (int i = fNQuant/2; i < fNQuant-1; ++i) {
00206       double x = estmedian + (i-fNQuant/2)*(fT1-estmedian)/(fNQuant/2-1);
00207       fQuant[i] = Cdf(x);
00208       fLambda[i] = x;
00209    }
00210    
00211    fQuant[0] = 0;
00212    fLambda[0] = fT0;
00213    fQuant[fNQuant-1] = 1;
00214    fLambda[fNQuant-1] = fT1;
00215      
00216 }
00217 
00218 double VavilovAccurate::Pdf (double x) const {
00219 
00220    static const double pi = 3.14159265358979323846;       // pi
00221 
00222    int n = int(fX0);
00223    double f;
00224    if (x < fT0) {
00225       f = 0;
00226    } else if (x <= fT1) {
00227       double y = x-fT0;
00228       double u = fOmega*y-pi;
00229       double cof = 2*cos(u);
00230       double a1 = 0;
00231       double a0 = fA_pdf[1];
00232       double a2 = 0;
00233       for (int k = 2; k <= n+1; ++k) {
00234          a2 = a1;
00235          a1 = a0;
00236          a0 = fA_pdf[k]+cof*a1-a2;
00237       }
00238       double b1 = 0;
00239       double b0 = fB_pdf[1];
00240       for (int k = 2; k <= n; ++k) {
00241          double b2 = b1;
00242          b1 = b0;
00243          b0 = fB_pdf[k]+cof*b1-b2;
00244       }
00245       f = 0.5*(a0-a2)+b0*sin(u);
00246    } else {
00247       f = 0;
00248    }
00249    return f;
00250 }
00251 
00252 double VavilovAccurate::Pdf (double x, double kappa, double beta2) {
00253    if (kappa != fKappa || beta2 != fBeta2) Set (kappa, beta2);
00254    return Pdf (x);
00255 }
00256 
00257 double VavilovAccurate::Cdf (double x) const {
00258 
00259    static const double pi = 3.14159265358979323846;       // pi
00260 
00261    int n = int(fX0);
00262    double f;
00263    if (x < fT0) {
00264       f = 0;
00265    } else if (x <= fT1) {
00266       double y = x-fT0;
00267       double u = fOmega*y-pi;
00268       double cof = 2*cos(u);
00269       double a1 = 0;
00270       double a0 = fA_cdf[1];
00271       double a2 = 0;
00272       for (int k = 2; k <= n+1; ++k) {
00273          a2 = a1;
00274          a1 = a0;
00275          a0 = fA_cdf[k]+cof*a1-a2;
00276       }
00277       double b1 = 0;
00278       double b0 = fB_cdf[1];
00279       for (int k = 2; k <= n; ++k) {
00280          double b2 = b1;
00281          b1 = b0;
00282          b0 = fB_cdf[k]+cof*b1-b2;
00283       }
00284       f = 0.5*(a0-a2)+b0*sin(u);
00285       f += y/fT;
00286    } else {
00287       f = 1;
00288    }
00289    return f;
00290 }
00291 
00292 double VavilovAccurate::Cdf (double x, double kappa, double beta2) {
00293    if (kappa != fKappa || beta2 != fBeta2) Set (kappa, beta2);
00294    return Cdf (x);
00295 }
00296 
00297 double VavilovAccurate::Cdf_c (double x) const {
00298 
00299    static const double pi = 3.14159265358979323846;       // pi
00300 
00301    int n = int(fX0);
00302    double f;
00303    if (x < fT0) {
00304       f = 1;
00305    } else if (x <= fT1) {
00306       double y = fT1-x;
00307       double u = fOmega*y-pi;
00308       double cof = 2*cos(u);
00309       double a1 = 0;
00310       double a0 = fA_cdf[1];
00311       double a2 = 0;
00312       for (int k = 2; k <= n+1; ++k) {
00313          a2 = a1;
00314          a1 = a0;
00315          a0 = fA_cdf[k]+cof*a1-a2;
00316       }
00317       double b1 = 0;
00318       double b0 = fB_cdf[1];
00319       for (int k = 2; k <= n; ++k) {
00320          double b2 = b1;
00321          b1 = b0;
00322          b0 = fB_cdf[k]+cof*b1-b2;
00323       }
00324       f = -0.5*(a0-a2)+b0*sin(u);
00325       f += y/fT;
00326    } else {
00327       f = 0;
00328    }
00329    return f;
00330 }
00331 
00332 double VavilovAccurate::Cdf_c (double x, double kappa, double beta2) {
00333    if (kappa != fKappa || beta2 != fBeta2) Set (kappa, beta2);
00334    return Cdf_c (x);
00335 }
00336 
00337 double VavilovAccurate::Quantile (double z) const {
00338    if (z < 0 || z > 1) return std::numeric_limits<double>::signaling_NaN();
00339   
00340    if (!fQuantileInit) InitQuantile();
00341 
00342    double x;
00343    if (fKappa < 0.02) {
00344       x = ROOT::Math::landau_quantile (z*(1-2*fEpsilonPM) + fEpsilonPM);
00345       if (x < fT0+5*fEpsilon) x = fT0+5*fEpsilon;
00346       else if (x > fT1-10*fEpsilon) x = fT1-10*fEpsilon;
00347    }
00348    else {
00349       // yes, I know what a binary search is, but linear search is faster for small n!
00350       int i = 1;
00351       while (z > fQuant[i]) ++i; 
00352       assert (i < fNQuant);
00353       
00354       assert (i >= 1);
00355       assert (i < fNQuant);
00356 
00357       // initial solution
00358       double f = (z-fQuant[i-1])/(fQuant[i]-fQuant[i-1]);
00359       assert (f >= 0);
00360       assert (f <= 1);
00361       assert (fQuant[i] > fQuant[i-1]);
00362    
00363       x = f*fLambda[i] + (1-f)*fLambda[i-1];
00364    }
00365    if (fabs(x-fT0) < fEpsilon || fabs(x-fT1) < fEpsilon) return x;
00366    
00367    assert (x > fT0 && x < fT1);
00368    double dx;
00369    int n = 0;
00370    do {
00371       ++n;
00372       double y = Cdf(x)-z;
00373       double y1 = Pdf (x);
00374       dx =  - y/y1;
00375       x = x + dx;
00376       // protect against shooting beyond the support
00377       if (x < fT0) x = 0.5*(fT0+x-dx);
00378       else if (x > fT1) x = 0.5*(fT1+x-dx);
00379       assert (x > fT0 && x < fT1);
00380    } while (fabs(dx) > fEpsilon && n < 100);
00381    return x;
00382 }
00383 
00384 double VavilovAccurate::Quantile (double z, double kappa, double beta2) {
00385    if (kappa != fKappa || beta2 != fBeta2) Set (kappa, beta2);
00386    return Quantile (z);
00387 }
00388 
00389 double VavilovAccurate::Quantile_c (double z) const {
00390    if (z < 0 || z > 1) return std::numeric_limits<double>::signaling_NaN();
00391   
00392    if (!fQuantileInit) InitQuantile();
00393    
00394    double z1 = 1-z;
00395 
00396    double x;
00397    if (fKappa < 0.02) {
00398       x = ROOT::Math::landau_quantile (z1*(1-2*fEpsilonPM) + fEpsilonPM);
00399       if (x < fT0+5*fEpsilon) x = fT0+5*fEpsilon;
00400       else if (x > fT1-10*fEpsilon) x = fT1-10*fEpsilon;
00401    }
00402    else {
00403       // yes, I know what a binary search is, but linear search is faster for small n!
00404       int i = 1;
00405       while (z1 > fQuant[i]) ++i; 
00406       assert (i < fNQuant);
00407    
00408 //       int i0=0, i1=fNQuant, i;
00409 //       for (int it = 0; it < LOG2fNQuant; ++it) {
00410 //         i = (i0+i1)/2;
00411 //         if (z > fQuant[i]) i0 = i;
00412 //         else i1 = i;
00413 //       }
00414 //       assert (i1-i0 == 1);
00415    
00416       assert (i >= 1);
00417       assert (i < fNQuant);
00418 
00419       // initial solution
00420       double f = (z1-fQuant[i-1])/(fQuant[i]-fQuant[i-1]);
00421       assert (f >= 0);
00422       assert (f <= 1);
00423       assert (fQuant[i] > fQuant[i-1]);
00424    
00425       x = f*fLambda[i] + (1-f)*fLambda[i-1];
00426    }
00427    if (fabs(x-fT0) < fEpsilon || fabs(x-fT1) < fEpsilon) return x;
00428    
00429    assert (x > fT0 && x < fT1);
00430    double dx;
00431    int n = 0;
00432    do {
00433       ++n;
00434       double y = Cdf_c(x)-z;
00435       double y1 = -Pdf (x);
00436       dx =  - y/y1;
00437       x = x + dx;
00438       // protect against shooting beyond the support
00439       if (x < fT0) x = 0.5*(fT0+x-dx);
00440       else if (x > fT1) x = 0.5*(fT1+x-dx);
00441       assert (x > fT0 && x < fT1);
00442    } while (fabs(dx) > fEpsilon && n < 100);
00443    return x;
00444 }
00445 
00446 double VavilovAccurate::Quantile_c (double z, double kappa, double beta2) {
00447    if (kappa != fKappa || beta2 != fBeta2) Set (kappa, beta2);
00448    return Quantile_c (z);
00449 }
00450 
00451 VavilovAccurate *VavilovAccurate::GetInstance() {
00452    if (!fgInstance) fgInstance = new VavilovAccurate (1, 1);
00453    return fgInstance;
00454 }
00455    
00456 VavilovAccurate *VavilovAccurate::GetInstance(double kappa, double beta2) {
00457    if (!fgInstance) fgInstance = new VavilovAccurate (kappa, beta2);
00458    else if (kappa != fgInstance->fKappa || beta2 != fgInstance->fBeta2) fgInstance->Set (kappa, beta2);
00459    return fgInstance;
00460 }
00461 
00462 double vavilov_accurate_pdf (double x, double kappa, double beta2) {
00463    VavilovAccurate *vavilov = VavilovAccurate::GetInstance (kappa, beta2);
00464    return vavilov->Pdf (x);
00465 }
00466 
00467 double vavilov_accurate_cdf_c (double x, double kappa, double beta2) {
00468    VavilovAccurate *vavilov = VavilovAccurate::GetInstance (kappa, beta2);
00469    return vavilov->Cdf_c (x);
00470 }
00471 
00472 double vavilov_accurate_cdf (double x, double kappa, double beta2) {
00473    VavilovAccurate *vavilov = VavilovAccurate::GetInstance (kappa, beta2);
00474    return vavilov->Cdf (x);
00475 }
00476 
00477 double vavilov_accurate_quantile (double z, double kappa, double beta2) {
00478    VavilovAccurate *vavilov = VavilovAccurate::GetInstance (kappa, beta2);
00479    return vavilov->Quantile (z);
00480 }
00481 
00482 double vavilov_accurate_quantile_c (double z, double kappa, double beta2) {
00483    VavilovAccurate *vavilov = VavilovAccurate::GetInstance (kappa, beta2);
00484    return vavilov->Quantile_c (z);
00485 }
00486 
00487 double VavilovAccurate::G116f1 (double x) const {
00488    // fH[1] = kappa*(2+beta2*eu) -ln(fEpsilon) + ln(2/pi**2)
00489    // fH[2] = beta2*kappa
00490    // fH[3] = omwga/kappa
00491    // fH[4] = pi/2 *fOmega
00492    // log of Eq. (4.10)
00493    return fH[1]+fH[2]*std::log(fH[3]*x)-fH[4]*x;
00494 }
00495 
00496 double VavilovAccurate::G116f2 (double x) const {
00497    // fH[5] = 1-beta2*(1-eu)-logEpsilonPM/kappa;       // eq. 3.9
00498    // fH[6] = beta2;
00499    // fH[7] = 1-beta2;
00500    // Eq. 3.7 of Schorr
00501 //   return fH[5]-x+fH[6]*(std::log(std::fabs(x))-ROOT::Math::expint (-x))-fH[7]*std::exp(-x);
00502    return fH[5]-x+fH[6]*E1plLog(x)-fH[7]*std::exp(-x);
00503 }
00504 
00505 int VavilovAccurate::Rzero (double a, double b, double& x0, 
00506                      double eps, int mxf, double (VavilovAccurate::*f)(double)const) const {
00507  
00508    double xa, xb, fa, fb, r;
00509  
00510    if (a <= b) {
00511       xa = a;
00512       xb = b;
00513    } else {
00514       xa = b;
00515       xb = a;
00516    }
00517    fa = (this->*f)(xa);
00518    fb = (this->*f)(xb);
00519    
00520    if(fa*fb > 0) {
00521       r = -2*(xb-xa);
00522       x0 = 0;
00523 //      std::cerr << "VavilovAccurate::Rzero: fail=2, f(" << a << ")=" << (this->*f) (a)
00524 //                << ", f(" << b << ")=" << (this->*f) (b) << std::endl;
00525       return 2;
00526    }
00527    int mc = 0;
00528    
00529    bool recalcF12 = true;
00530    bool recalcFab = true;
00531    bool fail      = false;
00532    
00533  
00534    double x1=0, x2=0, f1=0, f2=0, fx=0, ee=0;
00535    do {
00536       if (recalcF12) {
00537          x0 = 0.5*(xa+xb);
00538          r = x0-xa;
00539          ee = eps*(std::abs(x0)+1);
00540          if(r <= ee) break;
00541          f1 = fa;
00542          x1 = xa;
00543          f2 = fb;
00544          x2 = xb;
00545       }
00546       if (recalcFab) {
00547          fx = (this->*f)(x0);
00548          ++mc;
00549          if(mc > mxf) {
00550             fail = true;
00551             break;
00552          }
00553          if(fx*fa > 0) {
00554             xa = x0;
00555             fa = fx;
00556          } else {
00557             xb = x0;
00558             fb = fx;
00559          }
00560       }
00561       recalcF12 = true;
00562       recalcFab = true;
00563    
00564       double u1 = f1-f2;
00565       double u2 = x1-x2;
00566       double u3 = f2-fx;
00567       double u4 = x2-x0;
00568       if(u2 == 0 || u4 == 0) continue;
00569       double f3 = fx;
00570       double x3 = x0;
00571       u1 = u1/u2;
00572       u2 = u3/u4;
00573       double ca = u1-u2;
00574       double cb = (x1+x2)*u2-(x2+x0)*u1;
00575       double cc = (x1-x0)*f1-x1*(ca*x1+cb);
00576       if(ca == 0) {
00577          if(cb == 0) continue;
00578          x0 = -cc/cb;
00579       } else {
00580          u3 = cb/(2*ca);
00581          u4 = u3*u3-cc/ca;
00582          if(u4 < 0) continue;
00583          x0 = -u3 + (x0+u3 >= 0 ? +1 : -1)*std::sqrt(u4);
00584       }
00585       if(x0 < xa || x0 > xb) continue;
00586    
00587       recalcF12 = false;
00588  
00589       r = std::abs(x0-x3) < std::abs(x0-x2) ? std::abs(x0-x3) : std::abs(x0-x2);
00590       ee = eps*(std::abs(x0)+1);
00591       if (r > ee) {
00592          f1 = f2;
00593          x1 = x2;
00594          f2 = f3;
00595          x2 = x3;
00596          continue;
00597       }
00598       
00599       recalcFab = false;
00600  
00601       fx = (this->*f) (x0);
00602       if (fx == 0) break;
00603       double xx, ff;
00604       if (fx*fa < 0) {
00605          xx = x0-ee;
00606          if (xx <= xa) break;
00607          ff = (this->*f)(xx);
00608          fb = ff;
00609          xb = xx;
00610       } else {
00611          xx = x0+ee;
00612          if(xx >= xb) break;
00613          ff = (this->*f)(xx);
00614          fa = ff;
00615          xa = xx;
00616       }
00617       if (fx*ff <= 0) break;
00618       mc += 2;
00619       if (mc > mxf) {
00620          fail = true;
00621          break;
00622       }
00623       f1 = f3;
00624       x1 = x3;
00625       f2 = fx;
00626       x2 = x0;
00627       x0 = xx;
00628       fx = ff;
00629    }
00630    while (true);
00631    
00632    if (fail) {
00633       r = -0.5*std::abs(xb-xa);
00634       x0 = 0;
00635       std::cerr << "VavilovAccurate::Rzero: fail=" << fail << ", f(" << a << ")=" << (this->*f) (a)
00636                 << ", f(" << b << ")=" << (this->*f) (b) << std::endl;
00637       return 1;
00638    }
00639  
00640    r = ee;
00641    return 0;
00642 }  
00643     
00644 // Calculates log(|x|)+E_1(x)
00645 double VavilovAccurate::E1plLog (double x) {
00646    static const double eu = 0.577215664901532860606;      // Euler's constant
00647    double absx = std::fabs(x);
00648    if (absx < 1E-4) {
00649       return (x-0.25*x)*x-eu;
00650    }
00651    else if (x > 35) {
00652       return log (x);
00653    }
00654    else if (x < -50) {
00655       return -ROOT::Math::expint (-x);
00656    }
00657    return log(absx) -ROOT::Math::expint (-x);
00658 }
00659 
00660 double VavilovAccurate::GetLambdaMin() const {
00661    return fT0;
00662 }
00663 
00664 double VavilovAccurate::GetLambdaMax() const {
00665    return fT1;
00666 }
00667 
00668 double VavilovAccurate::GetKappa()     const {
00669    return fKappa;
00670 }
00671 
00672 double VavilovAccurate::GetBeta2()     const {
00673    return fBeta2;
00674 }
00675 
00676 double VavilovAccurate::Mode() const {
00677    double x = -4.22784335098467134e-01-std::log(fKappa)-fBeta2;
00678    if (x>-0.223172) x = -0.223172;
00679    double eps = 0.01;
00680    double dx;
00681   
00682    do {
00683       double p0 = Pdf (x - eps);
00684       double p1 = Pdf (x);
00685       double p2 = Pdf (x + eps);
00686       double y1 = 0.5*(p2-p0)/eps;
00687       double y2 = (p2-2*p1+p0)/(eps*eps);
00688       dx = - y1/y2;
00689       x += dx;
00690       if (fabs(dx) < eps) eps = 0.1*fabs(dx);
00691    } while (fabs(dx) > 1E-5);
00692    return x;
00693 }
00694 
00695 double VavilovAccurate::Mode(double kappa, double beta2) {
00696    if (kappa != fKappa || beta2 != fBeta2) Set (kappa, beta2);
00697    return Mode();
00698 }
00699 
00700 double VavilovAccurate::GetEpsilonPM() const {
00701    return fEpsilonPM;
00702 }
00703 
00704 double VavilovAccurate::GetEpsilon()   const {
00705    return fEpsilon;
00706 }
00707 
00708 double VavilovAccurate::GetNTerms()    const {
00709    return fX0;
00710 }
00711    
00712 
00713 
00714 } // namespace Math
00715 } // namespace ROOT

Generated on Tue Jul 5 14:34:57 2011 for ROOT_528-00b_version by  doxygen 1.5.1