NormalDistribution.cc
Go to the documentation of this file.
1 #include <cmath>
2 #include <limits>
3 #include <utl/NormalDistribution.h>
4 #include <utl/ErrorLogger.h>
5 
6 using namespace std;
7 
8 
9 namespace utl {
10 
18  double
19  InverseNormalCDF(const double p)
20  {
21  const double a[6] = {
22  -39.69683028665376,
23  220.9460984245205,
24  -275.9285104469687,
25  138.3577518672690,
26  -30.66479806614716,
27  2.506628277459239
28  };
29 
30  const double b[5] = {
31  -54.47609879822406,
32  161.5858368580409,
33  -155.6989798598866,
34  66.80131188771972,
35  -13.28068155288572
36  };
37 
38  const double c[6] = {
39  -0.007784894002430293,
40  -0.3223964580411365,
41  -2.400758277161838,
42  -2.549732539343734,
43  4.374664141464968,
44  2.938163982698783
45  };
46 
47  const double d[4] = {
48  0.007784695709041462,
49  0.3224671290700398,
50  2.445134137142996,
51  3.754408661907416
52  };
53 
54  if (p < 0 || p > 1) {
55  ERROR("Bad p in routine InverseNormalCDF");
56  return numeric_limits<double>::quiet_NaN();
57  }
58 
59  if (p == 0)
60  return -numeric_limits<double>::infinity();
61 
62  if (p == 1)
63  return numeric_limits<double>::infinity();
64 
65  // inverse normal cdf is an odd function
66 
67  const double pp = min(p, 1 - p);
68 
69  double x;
70 
71  // minmax rational approximations are better than 8 decimal places
72  if (pp <= 0.02425) {
73  const double q = sqrt(-2 * log(pp));
74  x =
75  (((((c[0]*q + c[1])*q + c[2])*q + c[3])*q + c[4])*q + c[5]) /
76  ((((d[0]*q + d[1])*q + d[2])*q + d[3])*q + 1);
77  } else {
78  const double q = pp - 0.5;
79  const double r = q*q;
80  x =
81  (((((a[0]*r + a[1])*r + a[2])*r + a[3])*r + a[4])*r + a[5])*q /
82  (((((b[0]*r + b[1])*r + b[2])*r + b[3])*r + b[4])*r + 1);
83  }
84 
85  // one step of Halley's iteration brings accuracy to the full machine precision.
86  const double df = NormalCDF(x) - pp;
87  const double dfof = df * sqrt(2*kPi) * exp(0.5*Sqr(x));
88  x -= dfof / (1 + 0.5*x*dfof);
89 
90  return p > 0.5 ? -x : x;
91  }
92 
93 
94  double
95  TruncatedNormalPDF(const double x, const double mu, const double sigma,
96  const double xmin, const double xmax)
97  {
98  if (xmin >= xmax || x < xmin || x > xmax)
99  return 0;
100  return NormalPDF(x, mu, sigma) / (NormalCDF(xmax, mu, sigma) - NormalCDF(xmin, mu, sigma));
101  }
102 
103 
104  // truncated gaussian with xmin = 0 and xmax = infinity
105  double
106  TruncatedNormalPDF(const double x, const double mu, const double sigma, const double xmin)
107  {
108  if (x <= xmin)
109  return 0;
110  return NormalPDF(x, mu, sigma) / (1 - NormalCDF(xmin, mu, sigma));
111  }
112 
113 }
constexpr T Sqr(const T &x)
double TruncatedNormalPDF(const double x, const double mu, const double sigma, const double xmin, const double xmax)
double InverseNormalCDF(const double p)
Inverse of the comulative normal distribution. Taken from http://home.online.no/~pjacklam/notes/invno...
double NormalPDF(const double x)
double NormalCDF(const double x)
constexpr double kPi
Definition: MathConstants.h:24
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165

, generated on Tue Sep 26 2023.