1 |
gezelter |
1767 |
/* |
2 |
|
|
* Borrowed from OpenMM. |
3 |
|
|
*/ |
4 |
|
|
|
5 |
|
|
#include "config.h" |
6 |
|
|
#ifndef MATH_ERFC_H |
7 |
|
|
#define MATH_ERFC_H |
8 |
|
|
|
9 |
|
|
/* |
10 |
|
|
* At least up to version 8 (VC++ 2005), Microsoft does not support the |
11 |
|
|
* standard C99 erf() and erfc() functions. For now we're including these |
12 |
|
|
* definitions for an MSVC compilation; if these are added later then |
13 |
|
|
* the #ifdef below should change to compare _MSC_VER with a particular |
14 |
|
|
* version level. |
15 |
|
|
*/ |
16 |
|
|
|
17 |
|
|
#ifdef _MSC_VER |
18 |
|
|
|
19 |
|
|
|
20 |
|
|
/*************************** |
21 |
|
|
* erf.cpp |
22 |
|
|
* author: Steve Strand |
23 |
|
|
* written: 29-Jan-04 |
24 |
|
|
***************************/ |
25 |
|
|
|
26 |
|
|
#include <cmath> |
27 |
|
|
|
28 |
|
|
static const RealType rel_error= 1E-12; //calculate 12 significant figures |
29 |
|
|
//you can adjust rel_error to trade off between accuracy and speed |
30 |
|
|
//but don't ask for > 15 figures (assuming usual 52 bit mantissa in a double) |
31 |
|
|
|
32 |
|
|
static RealType erfc(RealType x); |
33 |
|
|
|
34 |
|
|
static RealType erf(RealType x) |
35 |
|
|
//erf(x) = 2/sqrt(pi)*integral(exp(-t^2),t,0,x) |
36 |
|
|
// = 2/sqrt(pi)*[x - x^3/3 + x^5/5*2! - x^7/7*3! + ...] |
37 |
|
|
// = 1-erfc(x) |
38 |
|
|
{ |
39 |
|
|
static const RealType two_sqrtpi= 1.128379167095512574; // 2/sqrt(pi) |
40 |
|
|
if (fabs(x) > 2.2) { |
41 |
|
|
return 1.0 - erfc(x); //use continued fraction when fabs(x) > 2.2 |
42 |
|
|
} |
43 |
|
|
RealType sum= x, term= x, xsqr= x*x; |
44 |
|
|
int j= 1; |
45 |
|
|
do { |
46 |
|
|
term*= xsqr/j; |
47 |
|
|
sum-= term/(2*j+1); |
48 |
|
|
++j; |
49 |
|
|
term*= xsqr/j; |
50 |
|
|
sum+= term/(2*j+1); |
51 |
|
|
++j; |
52 |
|
|
} while (fabs(term)/sum > rel_error); |
53 |
|
|
return two_sqrtpi*sum; |
54 |
|
|
} |
55 |
|
|
|
56 |
|
|
|
57 |
|
|
static RealType erfc(RealType x) |
58 |
|
|
//erfc(x) = 2/sqrt(pi)*integral(exp(-t^2),t,x,inf) |
59 |
|
|
// = exp(-x^2)/sqrt(pi) * [1/x+ (1/2)/x+ (2/2)/x+ (3/2)/x+ (4/2)/x+ ...] |
60 |
|
|
// = 1-erf(x) |
61 |
|
|
//expression inside [] is a continued fraction so '+' means add to denominator only |
62 |
|
|
{ |
63 |
|
|
static const RealType one_sqrtpi= 0.564189583547756287; // 1/sqrt(pi) |
64 |
|
|
if (fabs(x) < 2.2) { |
65 |
|
|
return 1.0 - erf(x); //use series when fabs(x) < 2.2 |
66 |
|
|
} |
67 |
|
|
// Don't look for x==0 here! |
68 |
|
|
if (x < 0) { //continued fraction only valid for x>0 |
69 |
|
|
return 2.0 - erfc(-x); |
70 |
|
|
} |
71 |
|
|
RealType a=1, b=x; //last two convergent numerators |
72 |
|
|
RealType c=x, d=x*x+0.5; //last two convergent denominators |
73 |
|
|
RealType q1, q2= b/d; //last two convergents (a/c and b/d) |
74 |
|
|
RealType n= 1.0, t; |
75 |
|
|
do { |
76 |
|
|
t= a*n+b*x; |
77 |
|
|
a= b; |
78 |
|
|
b= t; |
79 |
|
|
t= c*n+d*x; |
80 |
|
|
c= d; |
81 |
|
|
d= t; |
82 |
|
|
n+= 0.5; |
83 |
|
|
q1= q2; |
84 |
|
|
q2= b/d; |
85 |
|
|
} while (fabs(q1-q2)/q2 > rel_error); |
86 |
|
|
return one_sqrtpi*exp(-x*x)*q2; |
87 |
|
|
} |
88 |
|
|
|
89 |
|
|
#endif // _MSC_VER |
90 |
|
|
|
91 |
|
|
#endif |