- Main Page
- Related Pages
- Classes
- Files

- File List

# MSVC_erfc.h

    00001 #ifndef OPENMM_MSVC_ERFC_H_
    00002 #define OPENMM_MSVC_ERFC_H_
    00003
    00004 /*
    00005  * Up to version 11 (VC++ 2012), Microsoft does not support the
    00006  * standard C99 erf() and erfc() functions so we have to fake them here.
    00007  * These were added in version 12 (VC++ 2013), which sets _MSC_VER=1800
    00008  * (VC11 has _MSC_VER=1700).
    00009  */
    00010
    00011 #if defined(_MSC_VER)
    00012 #ifndef M_PI
    00013 #define M_PI 3.14159265358979323846264338327950288
    00014 #endif
    00015
    00016 #if _MSC_VER <= 1700 // 1700 is VC11, 1800 is VC12
    00017 /***************************
    00018 *   erf.cpp
    00019 *   author:  Steve Strand
    00020 *   written: 29-Jan-04
    00021 ***************************/
    00022
    00023 #include <cmath>
    00024
    00025 static const double rel_error= 1E-12;        //calculate 12 significant figures
    00026 //you can adjust rel_error to trade off between accuracy and speed
    00027 //but don't ask for > 15 figures (assuming usual 52 bit mantissa in a double)
    00028
    00029 static double erfc(double x);
    00030
    00031 static double erf(double x)
    00032 //erf(x) = 2/sqrt(pi)*integral(exp(-t^2),t,0,x)
    00033 //       = 2/sqrt(pi)*[x - x^3/3 + x^5/5*2! - x^7/7*3! + ...]
    00034 //       = 1-erfc(x)
    00035 {
    00036     static const double two_sqrtpi=  1.128379167095512574;        // 2/sqrt(pi)
    00037     if (fabs(x) > 2.2) {
    00038         return 1.0 - erfc(x);        //use continued fraction when fabs(x) > 2.2
    00039     }
    00040     double sum= x, term= x, xsqr= x*x;
    00041     int j= 1;
    00042     do {
    00043         term*= xsqr/j;
    00044         sum-= term/(2*j+1);
    00045         ++j;
    00046         term*= xsqr/j;
    00047         sum+= term/(2*j+1);
    00048         ++j;
    00049     } while (fabs(term)/sum > rel_error);
    00050     return two_sqrtpi*sum;
    00051 }
    00052
    00053
    00054 static double erfc(double x)
    00055 //erfc(x) = 2/sqrt(pi)*integral(exp(-t^2),t,x,inf)
    00056 //        = exp(-x^2)/sqrt(pi) * [1/x+ (1/2)/x+ (2/2)/x+ (3/2)/x+ (4/2)/x+ ...]
    00057 //        = 1-erf(x)
    00058 //expression inside [] is a continued fraction so '+' means add to denominator only
    00059 {
    00060     static const double one_sqrtpi=  0.564189583547756287;        // 1/sqrt(pi)
    00061     if (fabs(x) < 2.2) {
    00062         return 1.0 - erf(x);        //use series when fabs(x) < 2.2
    00063     }
    00064     // Don't look for x==0 here!
    00065     if (x < 0) {               //continued fraction only valid for x>0
    00066         return 2.0 - erfc(-x);
    00067     }
    00068     double a=1, b=x;                //last two convergent numerators
    00069     double c=x, d=x*x+0.5;          //last two convergent denominators
    00070     double q1, q2= b/d;             //last two convergents (a/c and b/d)
    00071     double n= 1.0, t;
    00072     do {
    00073         t= a*n+b*x;
    00074         a= b;
    00075         b= t;
    00076         t= c*n+d*x;
    00077         c= d;
    00078         d= t;
    00079         n+= 0.5;
    00080         q1= q2;
    00081         q2= b/d;
    00082       } while (fabs(q1-q2)/q2 > rel_error);
    00083     return one_sqrtpi*exp(-x*x)*q2;
    00084 }
    00085
    00086 #endif // _MSC_VER <= 1700
    00087 #endif // _MSC_VER
    00088
    00089 #endif // OPENMM_MSVC_ERFC_H_