Isis 3 Programmer Reference
GaussianDistribution.cpp
Go to the documentation of this file.
1 
23 #include "GaussianDistribution.h"
24 #include "Message.h"
25 #include <string>
26 #include <iostream>
27 
28 using namespace std;
29 namespace Isis {
36  GaussianDistribution::GaussianDistribution(const double mean, const double standardDeviation) {
37  p_mean = mean;
38  p_stdev = standardDeviation;
39  }
40 
41 
50  double GaussianDistribution::Probability(const double value) {
51  // P(x) = 1/(sqrt(2*pi)*sigma)*e^(-1/2*((x-mu)/sigma)^2)
52  return std::exp(-0.5 * std::pow((value - p_mean) / p_stdev, 2)) / (std::sqrt(2 * PI) * p_stdev);
53  }
54 
55 
64  double GaussianDistribution::CumulativeDistribution(const double value) {
65  // returns for the two extremes
66  if(value == DBL_MIN) {
67  return 0.0;
68  }
69  else if(value == DBL_MAX) {
70  return 1.0;
71  }
72 
73  // normalize the value and calculate the area under the
74  // pdf's curve.
75  double x = (value - p_mean) / p_stdev;
76  double sum = 0.0,
77  pre = -1.0;
78  double fact = 1.0; // fact = n!
79  // use taylor series to compute the area to machine precesion
80  // i.e. if an iteration has no impact on the sum, none of the following
81  // ones will since they are monotonically decreasing
82  for(int n = 0; pre != sum; n++) {
83  pre = sum;
84  // the nth term is x^(2n+1)/( (2n+1)*n!*(-2)^n )
85  sum += std::pow(x, 2 * n + 1) / (fact * (2 * n + 1) * std::pow(-2.0, n));
86  fact *= n + 1;
87  }
88 
89  // return the percentage (100% based)
90  return 50.0 + 100.0 / std::sqrt(2.0 * PI) * sum;
91  }
92 
106  double GaussianDistribution::InverseCumulativeDistribution(const double percent) {
107  // the cutoff values used in the ICDF algorithm
108  static double lowCutoff = 2.425;
109  static double highCutoff = 97.575;
110 
111  if((percent < 0.0) || (percent > 100.0)) {
112  string m = "Argument percent outside of the range 0 to 100 in";
113  m += " [GaussianDistribution::InverseCumulativeDistribution]";
114  throw IException(IException::Programmer, m, _FILEINFO_);
115  }
116 
117  // for information on the following algorithm, go to the website
118  // specified above
119 
120  double x;
121 
122  if(percent == 0.0) {
123  return DBL_MIN;
124  }
125  else if(percent == 100.0) {
126  return DBL_MAX;
127  }
128 
129  if(percent < lowCutoff) {
130  double q = std::sqrt(-2.0 * std::log(percent / 100.0));
131  x = C(q) / D(q);
132  }
133  else if(percent < highCutoff) {
134  double q = percent / 100.0 - 0.5,
135  r = q * q;
136  x = A(r) * q / B(r);
137  }
138  else {
139  double q = std::sqrt(-2.0 * std::log(1.0 - percent / 100.0));
140  x = -1.0 * C(q) / D(q);
141  }
142 
143  // refine the calculated value using one iteration of Halley's method
144  // for full machine precision
145  double e = CumulativeDistribution(p_stdev * x + p_mean) - percent; // the error amount
146  double u = e * std::sqrt(2.0 * PI) * std::exp(-0.5 * x * x);
147  x = x - u / (1 + 0.5 * x * u);
148 
149  return p_stdev * x + p_mean;
150  }
151 
152  // The following methods are used to compute the ICDF
153  // see the InverseCumulativeDistribution method for
154  // more information
155 
156  double GaussianDistribution::A(const double x) {
157  static const double a[6] = { -39.69683028665376,
158  220.9460984245205,
159  -275.9285104469687,
160  138.3577518672690,
161  -30.66479806614716,
162  2.506628277459239
163  };
164 
165  return((((a[0] * x + a[1]) * x + a[2]) * x + a[3]) * x + a[4]) * x + a[5];
166  }
167 
168  double GaussianDistribution::B(const double x) {
169  static const double b[6] = { -54.47609879822406,
170  161.5858368580409,
171  -155.6989798598866,
172  66.80131188771972,
173  -13.28068155288572,
174  1.0
175  };
176 
177  return((((b[0] * x + b[1]) * x + b[2]) * x + b[3]) * x + b[4]) * x + b[5];
178  }
179 
180  double GaussianDistribution::C(const double x) {
181  static const double c[6] = { -0.007784894002430293,
182  -0.3223964580411365,
183  -2.400758277161838,
184  -2.549732539343734,
185  4.374664141464968,
186  2.938163982698783
187  };
188 
189  return((((c[0] * x + c[1]) * x + c[2]) * x + c[3]) * x + c[4]) * x + c[5];
190  }
191 
192  double GaussianDistribution::D(const double x) {
193  static const double d[5] = { 0.007784695709041462,
194  0.3224671290700398,
195  2.445134137142996,
196  3.754408661907416,
197  1.0
198  };
199 
200  return(((d[0] * x + d[1]) * x + d[2]) * x + d[3]) * x + d[4];
201  }
202 }
const double PI
The mathematical constant PI.
Definition: Constants.h:56
Namespace for the standard library.
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:40
Isis exception class.
Definition: IException.h:107
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31