⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 error.cpp

📁 强大的C++库
💻 CPP
字号:
/*! * \file * \brief Error functions - source file * \author Tony Ottosson, Pal Frenger and Adam Piatyszek * * ------------------------------------------------------------------------- * * IT++ - C++ library of mathematical, signal processing, speech processing, *        and communications classes and functions * * Copyright (C) 1995-2008  (see AUTHORS file for a list of contributors) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * ------------------------------------------------------------------------- */#include <itpp/base/math/error.h>#include <itpp/base/math/elem_math.h>#ifndef HAVE_ERFCdouble erfc(double Y){  int  ISW,I;  double P[4],Q[3],P1[6],Q1[5],P2[4],Q2[3];  double XMIN,XLARGE,SQRPI;  double X,RES,XSQ,XNUM,XDEN,XI,XBIG,ERFCret;  P[1]=0.3166529;  P[2]=1.722276;  P[3]=21.38533;  Q[1]=7.843746;  Q[2]=18.95226;  P1[1]=0.5631696;  P1[2]=3.031799;  P1[3]=6.865018;  P1[4]=7.373888;  P1[5]=4.318779e-5;  Q1[1]=5.354217;  Q1[2]=12.79553;  Q1[3]=15.18491;  Q1[4]=7.373961;  P2[1]=5.168823e-2;  P2[2]=0.1960690;  P2[3]=4.257996e-2;  Q2[1]=0.9214524;  Q2[2]=0.1509421;  XMIN=1.0E-5;  XLARGE=4.1875E0;  XBIG=9.0;  SQRPI=0.5641896;  X=Y;  ISW=1;  if (X<0) {    ISW=-1;    X=-X;  }  if (X<0.477) {    if (X>=XMIN) {      XSQ=X*X;      XNUM=(P[1]*XSQ+P[2])*XSQ+P[3];      XDEN=(XSQ+Q[1])*XSQ+Q[2];      RES=X*XNUM/XDEN;    }    else RES=X*P[3]/Q[2];    if (ISW==-1) RES=-RES;    RES=1.0-RES;    goto slut;  }  if (X>4.0) {    if (ISW>0) goto ulf;    if (X<XLARGE) goto eva;    RES=2.0;    goto slut;  }  XSQ=X*X;  XNUM=P1[5]*X+P1[1];  XDEN=X+Q1[1];  for(I=2;I<=4;I++) {    XNUM=XNUM*X+P1[I];    XDEN=XDEN*X+Q1[I];  }  RES=XNUM/XDEN;  goto elin; ulf:  	if (X>XBIG) goto fred; eva:  	XSQ=X*X;  XI=1.0/XSQ;  XNUM=(P2[1]*XI+P2[2])*XI+P2[3];  XDEN=XI+Q2[1]*XI+Q2[2];  RES=(SQRPI+XI*XNUM/XDEN)/X; elin:	RES=RES*exp(-XSQ);  if (ISW==-1) RES=2.0-RES;  goto slut; fred:	RES=0.0; slut:	ERFCret=RES;  return  ERFCret;}#endif#ifndef HAVE_ERFdouble erf(double x){  return (1.0 - ::erfc(x));}#endifnamespace itpp {  /*!   * Abramowitz and Stegun: Eq. (7.1.14) gives this continued fraction   * for erfc(z)   *   * erfc(z) = sqrt(pi).exp(-z^2).  1   1/2   1   3/2   2   5/2   *                               ---  ---  ---  ---  ---  --- ...   *                               z +  z +  z +  z +  z +  z +   *   * This is evaluated using Lentz's method, as described in the   * narative of Numerical Recipes in C.   *   * The continued fraction is true providing real(z) > 0. In practice   * we like real(z) to be significantly greater than 0, say greater   * than 0.5.   */  std::complex<double> cerfc_continued_fraction(const std::complex<double>& z)  {    const double tiny = std::numeric_limits<double>::min();    // first calculate z+ 1/2   1    //                    ---  --- ...    //                    z +  z +    std::complex<double> f(z);    std::complex<double> C(f);    std::complex<double> D(0.0);    std::complex<double> delta;    double a;    a = 0.0;    do {      a += 0.5;      D = z + a * D;      C = z + a / C;      if ((D.real() == 0.0) && (D.imag() == 0.0))        D = tiny;      D = 1.0 / D;      delta = C * D;      f = f * delta;    } while (abs(1.0 - delta) > eps);    // Do the first term of the continued fraction    f = 1.0 / f;    // and do the final scaling    f = f * exp(-z * z) / std::sqrt(pi);    return f;  }  //! Complementary function to \c cerfc_continued_fraction  std::complex<double> cerf_continued_fraction(const std::complex<double>& z)  {    if (z.real() > 0)      return 1.0 - cerfc_continued_fraction(z);    else      return -1.0 + cerfc_continued_fraction(-z);  }  /*!   * Abramawitz and Stegun: Eq. (7.1.5) gives a series for erf(z) good   * for all z, but converges faster for smallish abs(z), say abs(z) < 2.   */  std::complex<double> cerf_series(const std::complex<double>& z)  {    const double tiny = std::numeric_limits<double>::min();    std::complex<double> sum(0.0);    std::complex<double> term(z);    std::complex<double> z2(z*z);    for (int n = 0; (n < 3) || (abs(term) > abs(sum) * tiny); n++) {      sum += term / static_cast<double>(2 * n + 1);      term *= -z2 / static_cast<double>(n + 1);    }    return sum * 2.0 / std::sqrt(pi);  }  /*!   * Numerical Recipes quotes a formula due to Rybicki for evaluating   * Dawson's Integral:   *   * exp(-x^2) integral exp(t^2).dt = 1/sqrt(pi) lim  sum  exp(-(z-n.h)^2) / n   *            0 to x                           h->0 n odd   *   * This can be adapted to erf(z).   */  std::complex<double> cerf_rybicki(const std::complex<double>& z)  {    double h = 0.2; // numerical experiment suggests this is small enough    // choose an even n0, and then shift z->z-n0.h and n->n-h.    // n0 is chosen so that real((z-n0.h)^2) is as small as possible.    int n0 = 2 * static_cast<int>(z.imag() / (2 * h) + 0.5);    std::complex<double> z0(0.0, n0 * h);    std::complex<double> zp(z - z0);    std::complex<double> sum(0.0, 0.0);    // limits of sum chosen so that the end sums of the sum are    // fairly small. In this case exp(-(35.h)^2)=5e-22    for (int np = -35; np <= 35; np += 2) {      std::complex<double> t(zp.real(), zp.imag() - np * h);      std::complex<double> b(exp(t * t) / static_cast<double>(np + n0));      sum += b;    }    sum *= 2.0 * exp(-z * z) / pi;    return std::complex<double>(-sum.imag(), sum.real());  }  /*   * This function calculates a well known error function erf(z) for   * complex z. Three methods are implemented. Which one is used   * depends on z.   */  std::complex<double> erf(const std::complex<double>& z)  {    // Use the method appropriate to size of z -    // there probably ought to be an extra option for NaN z, or infinite z    if (abs(z) < 2.0)      return cerf_series(z);    else {      if (std::abs(z.real()) < 0.5)        return cerf_rybicki(z);      else        return cerf_continued_fraction(z);    }  }  double erfinv(double P)  {    double	Y,A,B,X,Z,W,WI,SN,SD,F,Z2,SIGMA;    double	A1=-.5751703,A2=-1.896513,A3=-.5496261E-1;    double	B0=-.1137730,B1=-3.293474,B2=-2.374996,B3=-1.187515;    double	C0=-.1146666,C1=-.1314774,C2=-.2368201,C3=.5073975e-1;    double	D0=-44.27977,D1=21.98546,D2=-7.586103;    double	E0=-.5668422E-1,E1=.3937021,E2=-.3166501,E3=.6208963E-1;    double	F0=-6.266786,F1=4.666263,F2=-2.962883;    double	G0=.1851159E-3,G1=-.2028152E-2,G2=-.1498384,G3=.1078639E-1;    double	H0=.9952975E-1,H1=.5211733,H2=-.6888301E-1;    //	double	RINFM=1.7014E+38;    X=P;    SIGMA = sign(X);    it_error_if(X<-1 || X>1,"erfinv : argument out of bounds");    Z=fabs(X);    if (Z>.85) {      A=1-Z;      B=Z;      W = std::sqrt(-log(A+A*B));      if (W>=2.5) {	if (W>=4.) {	  WI=1./W;	  SN=((G3*WI+G2)*WI+G1)*WI;	  SD=((WI+H2)*WI+H1)*WI+H0;	  F=W+W*(G0+SN/SD);	} else {	  SN=((E3*W+E2)*W+E1)*W;	  SD=((W+F2)*W+F1)*W+F0;	  F=W+W*(E0+SN/SD);	}      } else {	SN=((C3*W+C2)*W+C1)*W;	SD=((W+D2)*W+D1)*W+D0;	F=W+W*(C0+SN/SD);      }    } else {      Z2=Z*Z;      F=Z+Z*(B0+A1*Z2/(B1+Z2+A2/(B2+Z2+A3/(B3+Z2))));    }    Y=SIGMA*F;    return Y;  }  double Qfunc(double x)  {    return (0.5 * ::erfc(x / 1.41421356237310));  }} // namespace itpp

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -