Isis 3 Programmer Reference
GaussianDistribution.cpp
1
6/* SPDX-License-Identifier: CC0-1.0 */
7#include "GaussianDistribution.h"
8#include "Message.h"
9#include <string>
10#include <iostream>
11
12using namespace std;
13namespace Isis {
20 GaussianDistribution::GaussianDistribution(const double mean, const double standardDeviation) {
21 p_mean = mean;
22 p_stdev = standardDeviation;
23 }
24
25
34 double GaussianDistribution::Probability(const double value) {
35 // P(x) = 1/(sqrt(2*pi)*sigma)*e^(-1/2*((x-mu)/sigma)^2)
36 return std::exp(-0.5 * std::pow((value - p_mean) / p_stdev, 2)) / (std::sqrt(2 * PI) * p_stdev);
37 }
38
39
49 // returns for the two extremes
50 if(value == DBL_MIN) {
51 return 0.0;
52 }
53 else if(value == DBL_MAX) {
54 return 1.0;
55 }
56
57 // normalize the value and calculate the area under the
58 // pdf's curve.
59 double x = (value - p_mean) / p_stdev;
60 double sum = 0.0,
61 pre = -1.0;
62 double fact = 1.0; // fact = n!
63 // use taylor series to compute the area to machine precesion
64 // i.e. if an iteration has no impact on the sum, none of the following
65 // ones will since they are monotonically decreasing
66 for(int n = 0; pre != sum; n++) {
67 pre = sum;
68 // the nth term is x^(2n+1)/( (2n+1)*n!*(-2)^n )
69 sum += std::pow(x, 2 * n + 1) / (fact * (2 * n + 1) * std::pow(-2.0, n));
70 fact *= n + 1;
71 }
72
73 // return the percentage (100% based)
74 return 50.0 + 100.0 / std::sqrt(2.0 * PI) * sum;
75 }
76
91 // the cutoff values used in the ICDF algorithm
92 static double lowCutoff = 2.425;
93 static double highCutoff = 97.575;
94
95 if((percent < 0.0) || (percent > 100.0)) {
96 string m = "Argument percent outside of the range 0 to 100 in";
97 m += " [GaussianDistribution::InverseCumulativeDistribution]";
98 throw IException(IException::Programmer, m, _FILEINFO_);
99 }
100
101 // for information on the following algorithm, go to the website
102 // specified above
103
104 double x;
105
106 if(percent == 0.0) {
107 return DBL_MIN;
108 }
109 else if(percent == 100.0) {
110 return DBL_MAX;
111 }
112
113 if(percent < lowCutoff) {
114 double q = std::sqrt(-2.0 * std::log(percent / 100.0));
115 x = C(q) / D(q);
116 }
117 else if(percent < highCutoff) {
118 double q = percent / 100.0 - 0.5,
119 r = q * q;
120 x = A(r) * q / B(r);
121 }
122 else {
123 double q = std::sqrt(-2.0 * std::log(1.0 - percent / 100.0));
124 x = -1.0 * C(q) / D(q);
125 }
126
127 // refine the calculated value using one iteration of Halley's method
128 // for full machine precision
129 double e = CumulativeDistribution(p_stdev * x + p_mean) - percent; // the error amount
130 double u = e * std::sqrt(2.0 * PI) * std::exp(-0.5 * x * x);
131 x = x - u / (1 + 0.5 * x * u);
132
133 return p_stdev * x + p_mean;
134 }
135
136 // The following methods are used to compute the ICDF
137 // see the InverseCumulativeDistribution method for
138 // more information
139
140 double GaussianDistribution::A(const double x) {
141 static const double a[6] = { -39.69683028665376,
142 220.9460984245205,
143 -275.9285104469687,
144 138.3577518672690,
145 -30.66479806614716,
146 2.506628277459239
147 };
148
149 return((((a[0] * x + a[1]) * x + a[2]) * x + a[3]) * x + a[4]) * x + a[5];
150 }
151
152 double GaussianDistribution::B(const double x) {
153 static const double b[6] = { -54.47609879822406,
154 161.5858368580409,
155 -155.6989798598866,
156 66.80131188771972,
157 -13.28068155288572,
158 1.0
159 };
160
161 return((((b[0] * x + b[1]) * x + b[2]) * x + b[3]) * x + b[4]) * x + b[5];
162 }
163
164 double GaussianDistribution::C(const double x) {
165 static const double c[6] = { -0.007784894002430293,
166 -0.3223964580411365,
167 -2.400758277161838,
168 -2.549732539343734,
169 4.374664141464968,
170 2.938163982698783
171 };
172
173 return((((c[0] * x + c[1]) * x + c[2]) * x + c[3]) * x + c[4]) * x + c[5];
174 }
175
176 double GaussianDistribution::D(const double x) {
177 static const double d[5] = { 0.007784695709041462,
178 0.3224671290700398,
179 2.445134137142996,
180 3.754408661907416,
181 1.0
182 };
183
184 return(((d[0] * x + d[1]) * x + d[2]) * x + d[3]) * x + d[4];
185 }
186}
GaussianDistribution(const double mean=0.0, const double standardDeviation=1.0)
Constructs a gaussian distribution object.
double CumulativeDistribution(const double value)
Computes and returns the cumulative distribution up to the specified value on the gaussian distributi...
double Probability(const double value)
Computes and returns the probability of the specified value on the gaussian distribution.
double p_stdev
Value of the standard deviation.
double InverseCumulativeDistribution(const double percent)
Computes and returns the inverse cumulative distribution evaluated at the specified percentage value ...
double p_mean
Value of the mean.
Isis exception class.
Definition IException.h:91
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition IException.h:146
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
const double PI
The mathematical constant PI.
Definition Constants.h:40
Namespace for the standard library.