QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.34
Loading...
Searching...
No Matches
normaldistribution.hpp
Go to the documentation of this file.
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2002, 2003 Ferdinando Ametrano
5 Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl
6 Copyright (C) 2010 Kakhkhor Abdijalilov
7
8 This file is part of QuantLib, a free-software/open-source library
9 for financial quantitative analysts and developers - http://quantlib.org/
10
11 QuantLib is free software: you can redistribute it and/or modify it
12 under the terms of the QuantLib license. You should have received a
13 copy of the license along with this program; if not, please email
14 <quantlib-dev@lists.sf.net>. The license is also available online at
15 <http://quantlib.org/license.shtml>.
16
17 This program is distributed in the hope that it will be useful, but WITHOUT
18 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 FOR A PARTICULAR PURPOSE. See the license for more details.
20*/
21
22/*! \file normaldistribution.hpp
23 \brief normal, cumulative and inverse cumulative distributions
24*/
25
26#ifndef quantlib_normal_distribution_hpp
27#define quantlib_normal_distribution_hpp
28
30#include <ql/errors.hpp>
31
32namespace QuantLib {
33
34 //! Normal distribution function
35 /*! Given x, it returns its probability in a Gaussian normal distribution.
36 It provides the first derivative too.
37
38 \test the correctness of the returned value is tested by
39 checking it against numerical calculations. Cross-checks
40 are also performed against the
41 CumulativeNormalDistribution and InverseCumulativeNormal
42 classes.
43 */
45 public:
46 NormalDistribution(Real average = 0.0,
47 Real sigma = 1.0);
48 // function
49 Real operator()(Real x) const;
50 Real derivative(Real x) const;
51 private:
54 };
55
57
58
59 //! Cumulative normal distribution function
60 /*! Given x it provides an approximation to the
61 integral of the gaussian normal distribution:
62 formula here ...
63
64 For this implementation see M. Abramowitz and I. Stegun,
65 Handbook of Mathematical Functions,
66 Dover Publications, New York (1972)
67 */
69 public:
71 Real sigma = 1.0);
72 // function
73 Real operator()(Real x) const;
74 Real derivative(Real x) const;
75 private:
79 };
80
81
82 //! Inverse cumulative normal distribution function
83 /*! Given x between zero and one as
84 the integral value of a gaussian normal distribution
85 this class provides the value y such that
86 formula here ...
87
88 It use Acklam's approximation:
89 by Peter J. Acklam, University of Oslo, Statistics Division.
90 URL: http://home.online.no/~pjacklam/notes/invnorm/index.html
91
92 This class can also be used to generate a gaussian normal
93 distribution from a uniform distribution.
94 This is especially useful when a gaussian normal distribution
95 is generated from a low discrepancy uniform distribution:
96 in this case the traditional Box-Muller approach and its
97 variants would not preserve the sequence's low-discrepancy.
98
99 */
101 public:
102 InverseCumulativeNormal(Real average = 0.0,
103 Real sigma = 1.0);
104 // function
106 return average_ + sigma_*standard_value(x);
107 }
108 // value for average=0, sigma=1
109 /* Compared to operator(), this method avoids 2 floating point
110 operations (we use average=0 and sigma=1 most of the
111 time). The speed difference is noticeable.
112 */
114 Real z;
115 if (x < x_low_ || x_high_ < x) {
116 z = tail_value(x);
117 } else {
118 z = x - 0.5;
119 Real r = z*z;
120 z = (((((a1_*r+a2_)*r+a3_)*r+a4_)*r+a5_)*r+a6_)*z /
121 (((((b1_*r+b2_)*r+b3_)*r+b4_)*r+b5_)*r+1.0);
122 }
123
124 // The relative error of the approximation has absolute value less
125 // than 1.15e-9. One iteration of Halley's rational method (third
126 // order) gives full machine precision.
127 // #define REFINE_TO_FULL_MACHINE_PRECISION_USING_HALLEYS_METHOD
128 #ifdef REFINE_TO_FULL_MACHINE_PRECISION_USING_HALLEYS_METHOD
129 // error (f_(z) - x) divided by the cumulative's derivative
130 const Real r = (f_(z) - x) * M_SQRT2 * M_SQRTPI * exp(0.5 * z*z);
131 // Halley's method
132 z -= r/(1+0.5*z*r);
133 #endif
134
135 return z;
136 }
137 private:
138 /* Handling tails moved into a separate method, which should
139 make the inlining of operator() and standard_value method
140 easier. tail_value is called rarely and doesn't need to be
141 inlined.
142 */
143 static Real tail_value(Real x);
144 #if defined(QL_PATCH_SOLARIS)
146 #else
148 #endif
150 static const Real a1_;
151 static const Real a2_;
152 static const Real a3_;
153 static const Real a4_;
154 static const Real a5_;
155 static const Real a6_;
156 static const Real b1_;
157 static const Real b2_;
158 static const Real b3_;
159 static const Real b4_;
160 static const Real b5_;
161 static const Real c1_;
162 static const Real c2_;
163 static const Real c3_;
164 static const Real c4_;
165 static const Real c5_;
166 static const Real c6_;
167 static const Real d1_;
168 static const Real d2_;
169 static const Real d3_;
170 static const Real d4_;
171 static const Real x_low_;
172 static const Real x_high_;
173 };
174
175 // backward compatibility
177
178 //! Moro Inverse cumulative normal distribution class
179 /*! Given x between zero and one as
180 the integral value of a gaussian normal distribution
181 this class provides the value y such that
182 formula here ...
183
184 It uses Beasly and Springer approximation, with an improved
185 approximation for the tails. See Boris Moro,
186 "The Full Monte", 1995, Risk Magazine.
187
188 This class can also be used to generate a gaussian normal
189 distribution from a uniform distribution.
190 This is especially useful when a gaussian normal distribution
191 is generated from a low discrepancy uniform distribution:
192 in this case the traditional Box-Muller approach and its
193 variants would not preserve the sequence's low-discrepancy.
194
195 Peter J. Acklam's approximation is better and is available
196 as QuantLib::InverseCumulativeNormal
197 */
199 public:
200 MoroInverseCumulativeNormal(Real average = 0.0,
201 Real sigma = 1.0);
202 // function
203 Real operator()(Real x) const;
204 private:
206 static const Real a0_;
207 static const Real a1_;
208 static const Real a2_;
209 static const Real a3_;
210 static const Real b0_;
211 static const Real b1_;
212 static const Real b2_;
213 static const Real b3_;
214 static const Real c0_;
215 static const Real c1_;
216 static const Real c2_;
217 static const Real c3_;
218 static const Real c4_;
219 static const Real c5_;
220 static const Real c6_;
221 static const Real c7_;
222 static const Real c8_;
223 };
224
225 //! Maddock's Inverse cumulative normal distribution class
226 /*! Given x between zero and one as
227 the integral value of a gaussian normal distribution
228 this class provides the value y such that
229 formula here ...
230
231 From the boost documentation:
232 These functions use a rational approximation devised by
233 John Maddock to calculate an initial approximation to the
234 result that is accurate to ~10^-19, then only if that has
235 insufficient accuracy compared to the epsilon for type double,
236 do we clean up the result using Halley iteration.
237 */
239 public:
241 Real sigma = 1.0);
242 Real operator()(Real x) const;
243
244 private:
246 };
247
248 //! Maddock's cumulative normal distribution class
250 public:
251 MaddockCumulativeNormal(Real average = 0.0,
252 Real sigma = 1.0);
253 Real operator()(Real x) const;
254
255 private:
257 };
258
259
260 // inline definitions
261
263 Real sigma)
264 : average_(average), sigma_(sigma) {
265
266 QL_REQUIRE(sigma_>0.0,
267 "sigma must be greater than 0.0 ("
268 << sigma_ << " not allowed)");
269
273 }
274
276 Real deltax = x-average_;
277 Real exponent = -(deltax*deltax)/denominator_;
278 // debian alpha had some strange problem in the very-low range
279 return exponent <= -690.0 ? 0.0 : // exp(x) < 1.0e-300 anyway
280 Real(normalizationFactor_*std::exp(exponent));
281 }
282
284 return ((*this)(x) * (average_ - x)) / derNormalizationFactor_;
285 }
286
288 Real average, Real sigma)
289 : average_(average), sigma_(sigma) {
290
291 QL_REQUIRE(sigma_>0.0,
292 "sigma must be greater than 0.0 ("
293 << sigma_ << " not allowed)");
294 }
295
297 Real xn = (x - average_) / sigma_;
298 return gaussian_(xn) / sigma_;
299 }
300
302 Real average, Real sigma)
303 : average_(average), sigma_(sigma) {
304
305 QL_REQUIRE(sigma_>0.0,
306 "sigma must be greater than 0.0 ("
307 << sigma_ << " not allowed)");
308 }
309
311 Real average, Real sigma)
312 : average_(average), sigma_(sigma) {
313
314 QL_REQUIRE(sigma_>0.0,
315 "sigma must be greater than 0.0 ("
316 << sigma_ << " not allowed)");
317 }
318
319}
320
321
322#endif
Cumulative normal distribution function.
CumulativeNormalDistribution(Real average=0.0, Real sigma=1.0)
Inverse cumulative normal distribution function.
InverseCumulativeNormal(Real average=0.0, Real sigma=1.0)
static const CumulativeNormalDistribution f_
Maddock's cumulative normal distribution class.
Maddock's Inverse cumulative normal distribution class.
Moro Inverse cumulative normal distribution class.
MoroInverseCumulativeNormal(Real average=0.0, Real sigma=1.0)
Normal distribution function.
NormalDistribution(Real average=0.0, Real sigma=1.0)
Error function.
Classes and functions for error handling.
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
Definition: errors.hpp:117
QL_REAL Real
real number
Definition: types.hpp:50
Real sigma
#define M_SQRTPI
#define M_SQRT_2
#define M_SQRT2
#define M_1_SQRTPI
Definition: any.hpp:35
InverseCumulativeNormal InvCumulativeNormalDistribution
NormalDistribution GaussianDistribution
ext::shared_ptr< YieldTermStructure > r