lib/geomatics/SpecialFunctions.hpp

Go to the documentation of this file.
00001 #pragma ident "$Id: SpecialFunctions.hpp 292 2009-09-02 20:29:30Z BrianTolman $"
00002 
00003 //============================================================================
00004 //
00005 //  This file is part of GPSTk, the GPS Toolkit.
00006 //
00007 //  The GPSTk is free software; you can redistribute it and/or modify
00008 //  it under the terms of the GNU Lesser General Public License as published
00009 //  by the Free Software Foundation; either version 2.1 of the License, or
00010 //  any later version.
00011 //
00012 //  The GPSTk is distributed in the hope that it will be useful,
00013 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 //  GNU Lesser General Public License for more details.
00016 //
00017 //  You should have received a copy of the GNU Lesser General Public
00018 //  License along with GPSTk; if not, write to the Free Software Foundation,
00019 //  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
00020 //  
00021 //  Copyright 2004, The University of Texas at Austin
00022 //
00023 //============================================================================
00024 //============================================================================
00025 //
00026 // This software developed by Applied Research Laboratories at the University
00027 // of Texas at Austin, under contract to an agency or agencies within the U.S. 
00028 // Department of Defense. The U.S. Government retains all rights to use,
00029 // duplicate, distribute, disclose, or release this software. 
00030 //
00031 // Pursuant to DoD Directive 523024 
00032 //
00033 // DISTRIBUTION STATEMENT A: This software has been approved for public 
00034 //                           release, distribution is unlimited.
00035 //
00036 //=============================================================================
00037 
00045 #ifndef SPECIAL_FUNCTIONS_INCLUDE
00046 #define SPECIAL_FUNCTIONS_INCLUDE
00047 
00048 #include <cmath>
00049 #include <limits>
00050 #include "Exception.hpp"
00051 
00052 namespace gpstk
00053 {
00059    double lnGamma(const double& x) throw(Exception)
00060    {
00061       static const double con[8] = {
00062          76.18009172947146, -86.50532032941677, 24.01409824083091,
00063          -1.231739572450155, 1.208650973866179e-3, -5.395239384953e-6,
00064          1.000000000190015, 2.5066282746310005 };
00065       if(x <= 0) {
00066          Exception e("Non-positive argument in lnGamma()");
00067          GPSTK_THROW(e);
00068       }
00069       double y(x);
00070       double t(x+5.5);
00071       t -= (x+0.5) * ::log(t);
00072       double s(con[6]);
00073       for(int i=0; i<=5; i++) s += con[i] / ++y;
00074       return (-t + ::log(con[7]*s/x));
00075    }
00076 
00081    double factorial(const int& n) throw(Exception)
00082    {
00083       if(n < 0) {
00084          Exception e("Negative argument in factorial()");
00085          GPSTK_THROW(e);
00086       }
00087 
00088       if(n > 32) return ::exp(lnGamma(double(n+1)));
00089 
00090       static double store[33] = { 1.0, 1.0, 2.0, 6.0, 24.0, 120.0 };
00091       static int nstore=5;
00092 
00093       while(nstore < n) {
00094          int i = nstore++;
00095          store[nstore] = store[i] * nstore;
00096       }
00097 
00098       return store[n];
00099    }
00100 
00105    double lnFactorial(const int& n) throw(Exception)
00106    {
00107       if(n < 0) {
00108          Exception e("Negative argument in lnFactorial()");
00109          GPSTK_THROW(e);
00110       }
00111       if(n <= 1) return 0.0;
00112       return lnGamma(double(n+1));
00113    }
00114 
00123    double binomialCoeff(const int& n, const int& k) throw(Exception)
00124    {
00125       if(n < 0 || k > n) {
00126          Exception e("Invalid arguments in binomialCoeff()"); 
00127          GPSTK_THROW(e);
00128       }
00129 
00130       if(n <= 32)
00131          return (factorial(n) / (factorial(k)*factorial(n-k)));
00132 
00133       return floor(0.5 + ::exp(lnFactorial(n)-lnFactorial(k)-lnFactorial(n-k)));
00134    }
00135 
00142    double beta(const double& x, const double& y) throw(Exception)
00143    {
00144       try {
00145          return ::exp(lnGamma(x) + lnGamma(y) - lnGamma(x+y));
00146       }
00147       catch(Exception& e) {
00148          e.addText("Called by beta(x,y)");
00149          GPSTK_RETHROW(e);
00150       }
00151    }
00152 
00159    double seriesIncompGamma(const double& a, const double& x) throw(Exception)
00160    {
00161       if(x < 0) {
00162          Exception e("Negative first argument in seriesIncompGamma()");
00163          GPSTK_THROW(e);
00164       }
00165       if(a <= 0) {
00166          Exception e("Non-positive second argument in seriesIncompGamma()");
00167          GPSTK_THROW(e);
00168       }
00169 
00170       double lngamma(lnGamma(a));
00171 
00172       static const int imax(100);
00173       static const double eps(10*std::numeric_limits<double>().epsilon());
00174 
00175       double atmp(a),sum(1.0/a);
00176       double del(sum);
00177       for(int i=1; i<=imax; i++) {
00178          ++atmp;
00179          del *= x/atmp;
00180          sum += del;
00181          if(::fabs(del) < ::fabs(sum)*eps)
00182             return (sum * ::exp(-x + a * ::log(x) - lngamma));
00183       }
00184       Exception e("Overflow in seriesIncompGamma; first arg too big");
00185       GPSTK_THROW(e);
00186 
00187       return 0.0;
00188    }
00189 
00196    double contfracIncompGamma(const double& a, const double& x) throw(Exception)
00197    {
00198       if(x < 0) {
00199          Exception e("Negative first argument in contfracIncompGamma()");
00200          GPSTK_THROW(e);
00201       }
00202       if(a <= 0) {
00203          Exception e("Non-positive second argument in contfracIncompGamma()");
00204          GPSTK_THROW(e);
00205       }
00206 
00207       double lngamma(lnGamma(a));
00208 
00209       static const int imax(100);
00210       static const double eps(10*std::numeric_limits<double>().epsilon());
00211       static const double fpmin(10*std::numeric_limits<double>().min());
00212 
00213       double b(x+1.0-a),c(1.0/fpmin);
00214       double d(1.0/b);
00215       double h(d);
00216       int i;
00217       for(i=1; i<=imax; i++) {
00218          double an(-i*(i-a));
00219          b += 2.0;
00220          d = an*d+b;
00221          if(::fabs(d) < fpmin) d=fpmin;
00222          c = b+an/c;
00223          if(::fabs(c) < fpmin) c=fpmin;
00224          d = 1.0/d;
00225          double del(d*c);
00226          h *= del;
00227          if(::fabs(del-1.0) < eps) break;
00228       }
00229       if(i > imax) {
00230          Exception e("Overflow in contfracIncompGamma; first arg too big");
00231          GPSTK_THROW(e);
00232       }
00233 
00234       return (::exp(-x + a * ::log(x) - lngamma) * h);
00235    }
00236 
00243    double incompGamma(const double& a, const double& x) throw(Exception)
00244    {
00245       if(x < 0) {
00246          Exception e("Negative first argument in incompGamma()");
00247          GPSTK_THROW(e);
00248       }
00249       if(a <= 0) {
00250          Exception e("Non-positive second argument in incompGamma()");
00251          GPSTK_THROW(e);
00252       }
00253 
00254       if(x < a+1.0)
00255          return seriesIncompGamma(a,x);
00256       else
00257          return (1.0 - contfracIncompGamma(a,x));
00258    }
00259 
00266    double compIncompGamma(const double& a, const double& x) throw(Exception)
00267    {
00268       if(x < 0) {
00269          Exception e("Negative first argument in compIncompGamma()");
00270          GPSTK_THROW(e);
00271       }
00272       if(a <= 0) {
00273          Exception e("Non-positive second argument in compIncompGamma()");
00274          GPSTK_THROW(e);
00275       }
00276 
00277       if(x < a+1.0)
00278          return (1.0 - seriesIncompGamma(a,x));
00279       else
00280          return contfracIncompGamma(a,x);
00281    }
00282 
00286    double errorFunc(const double& x) throw(Exception)
00287    {
00288       if(x < 0) {
00289          Exception e("Negative first argument in errorFunc()");
00290          GPSTK_THROW(e);
00291       }
00292       try {
00293          return (x < 0.0 ? -incompGamma(0.5,x*x) : incompGamma(0.5,x*x));
00294       }
00295       catch(Exception& e) {
00296          e.addText("Called by errorFunc()");
00297          GPSTK_RETHROW(e);
00298       }
00299    }
00300 
00304    double compErrorFunc(const double& x) throw(Exception)
00305    {
00306       if(x < 0) {
00307          Exception e("Negative first argument in compErrorFunc()");
00308          GPSTK_THROW(e);
00309       }
00310       try {
00311          return (x < 0.0 ? 1.0+incompGamma(0.5,x*x) : compIncompGamma(0.5,x*x));
00312       }
00313       catch(Exception& e) {
00314          e.addText("Called by compErrorFunc()");
00315          GPSTK_RETHROW(e);
00316       }
00317    }
00318 
00325    double ChisqProbability(const double& x, const int& n) throw(Exception)
00326    {
00327       if(x <= 0) {
00328          Exception e("Non-positive chi-sq argument in ChisqProbability()");
00329          GPSTK_THROW(e);
00330       }
00331       if(n < 0) {
00332          Exception e("Non-positive degrees of freedom in ChisqProbability()");
00333          GPSTK_THROW(e);
00334       }
00335 
00336       return incompGamma(double(n)/2.0,x/2.0);
00337    }
00338 
00345    double CompChisqProbability(const double& x, const int& n) throw(Exception)
00346    {
00347       if(x <= 0) {
00348          Exception e("Non-positive chi-sq argument in CompChisqProbability()");
00349          GPSTK_THROW(e);
00350       }
00351       if(n < 0) {
00352          Exception e("Non-positive degrees of freedom in CompChisqProbability()");
00353          GPSTK_THROW(e);
00354       }
00355 
00356       return compIncompGamma(double(n)/2.0,x/2.0);
00357    }
00358 
00359    // Compute continued fractions portion of incomplete beta function I_x(a,b)
00361    double cfIBeta(const double& x, const double& a, const double& b) throw(Exception)
00362    {
00363       static const int imax(100);
00364       static const double eps(10*std::numeric_limits<double>().epsilon());
00365       static const double fpmin(10*std::numeric_limits<double>().min());
00366       const double qab(a+b);
00367       const double qap(a+1.0);
00368       const double qam(a-1.0);
00369       double c(1),d(1-qab*x/qap),aa,del;
00370       if(::fabs(d) < fpmin) d=fpmin;
00371       d = 1.0/d;
00372       double h(d);
00373       int i,i2;
00374       for(i=1; i<=imax; i++) {
00375          i2 = 2*i;
00376          aa = i*(b-i)*x/((qam+i2)*(a+i2));
00377          d = 1.0 + aa*d;
00378          if(::fabs(d) < fpmin) d=fpmin;
00379          c = 1.0 + aa/c;
00380          if(::fabs(c) < fpmin) c=fpmin;
00381          d = 1.0/d;
00382          h *= d*c;
00383          aa = -(a+i)*(qab+i)*x/((a+i2)*(qap+i2));
00384          d = 1.0 + aa*d;
00385          if(::fabs(d) < fpmin) d=fpmin;
00386          c = 1.0 + aa/c;
00387          if(::fabs(c) < fpmin) c=fpmin;
00388          d = 1.0/d;
00389          del = d*c;
00390          h *= del;
00391          if(::fabs(del-1.0) < eps) break;
00392       }
00393       if(i > imax) {
00394          Exception e("Overflow in cfIBeta(); a or b too big");
00395          GPSTK_THROW(e);
00396       }
00397       return h;
00398    }
00399 
00406    double incompleteBeta(const double& x, const double& a, const double& b)
00407       throw(Exception)
00408    {
00409       if(x < 0 || x > 1) {
00410          Exception e("Invalid x argument in incompleteBeta()");
00411          GPSTK_THROW(e);
00412       }
00413       if(a <= 0 || b <= 0) {
00414          Exception e("Non-positive argument in incompleteBeta()");
00415          GPSTK_THROW(e);
00416       }
00417 
00418       if(x == 0) return 0.0;
00419       if(x == 1) return 1.0;
00420 
00421       try {
00422          double factor = ::exp(lnGamma(a+b) - lnGamma(a) - lnGamma(b)
00423                                     + a * ::log(x) + b * ::log(1.0-x));
00424          if(x < (a+1.0)/(a+b+2.0))
00425             return factor*cfIBeta(x,a,b)/a;
00426          else
00427             return 1.0-factor*cfIBeta(1.0-x,b,a)/b;
00428       }
00429       catch(Exception& e) {
00430          e.addText("Called by incompleteBeta()");
00431          GPSTK_RETHROW(e);
00432       }
00433    }
00434 
00446    double StudentsDistProbability(const double& t, const int& n) throw(Exception)
00447    {
00448       if(n <= 0) {
00449          Exception e("Non-positive degrees of freedom in StudentsDistribution()");
00450          GPSTK_THROW(e);
00451       }
00452 
00453       return (1.0 - incompleteBeta(double(n)/(t*t+double(n)),double(n)/2,0.5));
00454    }
00455 
00472    double FDistProbability(const double& f, const int& n1, const int& n2)
00473       throw(Exception)
00474    {
00475       if(f < 0) {
00476          Exception e("Negative statistic in FDistribution()");
00477          GPSTK_THROW(e);
00478       }
00479       if(n1 <= 0 || n2 <= 0) {
00480          Exception e("Non-positive degrees of freedom in FDistribution()");
00481          GPSTK_THROW(e);
00482       }
00483 
00484       return incompleteBeta(double(n2)/(double(n2)+double(n1)*f),
00485                                       double(n2)/2.0,double(n1)/2.0);
00486    }
00487 
00488 }  // end namespace
00489 
00490 #endif // SPECIAL_FUNCTIONS_INCLUDE

Generated on Mon May 20 03:31:12 2013 for GPS ToolKit Software Library by  doxygen 1.3.9.1