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