]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // (C) Copyright John Maddock 2006. |
2 | // Use, modification and distribution are subject to the | |
3 | // Boost Software License, Version 1.0. (See accompanying file | |
4 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
5 | ||
6 | #ifndef BOOST_MATH_SF_ERF_INV_HPP | |
7 | #define BOOST_MATH_SF_ERF_INV_HPP | |
8 | ||
9 | #ifdef _MSC_VER | |
10 | #pragma once | |
11 | #pragma warning(push) | |
12 | #pragma warning(disable:4127) // Conditional expression is constant | |
13 | #pragma warning(disable:4702) // Unreachable code: optimization warning | |
14 | #endif | |
15 | ||
16 | namespace boost{ namespace math{ | |
17 | ||
18 | namespace detail{ | |
19 | // | |
20 | // The inverse erf and erfc functions share a common implementation, | |
21 | // this version is for 80-bit long double's and smaller: | |
22 | // | |
23 | template <class T, class Policy> | |
24 | T erf_inv_imp(const T& p, const T& q, const Policy&, const boost::mpl::int_<64>*) | |
25 | { | |
26 | BOOST_MATH_STD_USING // for ADL of std names. | |
27 | ||
28 | T result = 0; | |
29 | ||
30 | if(p <= 0.5) | |
31 | { | |
32 | // | |
33 | // Evaluate inverse erf using the rational approximation: | |
34 | // | |
35 | // x = p(p+10)(Y+R(p)) | |
36 | // | |
37 | // Where Y is a constant, and R(p) is optimised for a low | |
38 | // absolute error compared to |Y|. | |
39 | // | |
40 | // double: Max error found: 2.001849e-18 | |
41 | // long double: Max error found: 1.017064e-20 | |
42 | // Maximum Deviation Found (actual error term at infinite precision) 8.030e-21 | |
43 | // | |
44 | static const float Y = 0.0891314744949340820313f; | |
45 | static const T P[] = { | |
46 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.000508781949658280665617), | |
47 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.00836874819741736770379), | |
48 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.0334806625409744615033), | |
49 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.0126926147662974029034), | |
50 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.0365637971411762664006), | |
51 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.0219878681111168899165), | |
52 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.00822687874676915743155), | |
53 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.00538772965071242932965) | |
54 | }; | |
55 | static const T Q[] = { | |
56 | BOOST_MATH_BIG_CONSTANT(T, 64, 1.0), | |
57 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.970005043303290640362), | |
58 | BOOST_MATH_BIG_CONSTANT(T, 64, -1.56574558234175846809), | |
59 | BOOST_MATH_BIG_CONSTANT(T, 64, 1.56221558398423026363), | |
60 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.662328840472002992063), | |
61 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.71228902341542847553), | |
62 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.0527396382340099713954), | |
63 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.0795283687341571680018), | |
64 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.00233393759374190016776), | |
65 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.000886216390456424707504) | |
66 | }; | |
67 | T g = p * (p + 10); | |
68 | T r = tools::evaluate_polynomial(P, p) / tools::evaluate_polynomial(Q, p); | |
69 | result = g * Y + g * r; | |
70 | } | |
71 | else if(q >= 0.25) | |
72 | { | |
73 | // | |
74 | // Rational approximation for 0.5 > q >= 0.25 | |
75 | // | |
76 | // x = sqrt(-2*log(q)) / (Y + R(q)) | |
77 | // | |
78 | // Where Y is a constant, and R(q) is optimised for a low | |
79 | // absolute error compared to Y. | |
80 | // | |
81 | // double : Max error found: 7.403372e-17 | |
82 | // long double : Max error found: 6.084616e-20 | |
83 | // Maximum Deviation Found (error term) 4.811e-20 | |
84 | // | |
85 | static const float Y = 2.249481201171875f; | |
86 | static const T P[] = { | |
87 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.202433508355938759655), | |
88 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.105264680699391713268), | |
89 | BOOST_MATH_BIG_CONSTANT(T, 64, 8.37050328343119927838), | |
90 | BOOST_MATH_BIG_CONSTANT(T, 64, 17.6447298408374015486), | |
91 | BOOST_MATH_BIG_CONSTANT(T, 64, -18.8510648058714251895), | |
92 | BOOST_MATH_BIG_CONSTANT(T, 64, -44.6382324441786960818), | |
93 | BOOST_MATH_BIG_CONSTANT(T, 64, 17.445385985570866523), | |
94 | BOOST_MATH_BIG_CONSTANT(T, 64, 21.1294655448340526258), | |
95 | BOOST_MATH_BIG_CONSTANT(T, 64, -3.67192254707729348546) | |
96 | }; | |
97 | static const T Q[] = { | |
98 | BOOST_MATH_BIG_CONSTANT(T, 64, 1.0), | |
99 | BOOST_MATH_BIG_CONSTANT(T, 64, 6.24264124854247537712), | |
100 | BOOST_MATH_BIG_CONSTANT(T, 64, 3.9713437953343869095), | |
101 | BOOST_MATH_BIG_CONSTANT(T, 64, -28.6608180499800029974), | |
102 | BOOST_MATH_BIG_CONSTANT(T, 64, -20.1432634680485188801), | |
103 | BOOST_MATH_BIG_CONSTANT(T, 64, 48.5609213108739935468), | |
104 | BOOST_MATH_BIG_CONSTANT(T, 64, 10.8268667355460159008), | |
105 | BOOST_MATH_BIG_CONSTANT(T, 64, -22.6436933413139721736), | |
106 | BOOST_MATH_BIG_CONSTANT(T, 64, 1.72114765761200282724) | |
107 | }; | |
108 | T g = sqrt(-2 * log(q)); | |
109 | T xs = q - 0.25f; | |
110 | T r = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs); | |
111 | result = g / (Y + r); | |
112 | } | |
113 | else | |
114 | { | |
115 | // | |
116 | // For q < 0.25 we have a series of rational approximations all | |
117 | // of the general form: | |
118 | // | |
119 | // let: x = sqrt(-log(q)) | |
120 | // | |
121 | // Then the result is given by: | |
122 | // | |
123 | // x(Y+R(x-B)) | |
124 | // | |
125 | // where Y is a constant, B is the lowest value of x for which | |
126 | // the approximation is valid, and R(x-B) is optimised for a low | |
127 | // absolute error compared to Y. | |
128 | // | |
129 | // Note that almost all code will really go through the first | |
130 | // or maybe second approximation. After than we're dealing with very | |
131 | // small input values indeed: 80 and 128 bit long double's go all the | |
132 | // way down to ~ 1e-5000 so the "tail" is rather long... | |
133 | // | |
134 | T x = sqrt(-log(q)); | |
135 | if(x < 3) | |
136 | { | |
137 | // Max error found: 1.089051e-20 | |
138 | static const float Y = 0.807220458984375f; | |
139 | static const T P[] = { | |
140 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.131102781679951906451), | |
141 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.163794047193317060787), | |
142 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.117030156341995252019), | |
143 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.387079738972604337464), | |
144 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.337785538912035898924), | |
145 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.142869534408157156766), | |
146 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.0290157910005329060432), | |
147 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.00214558995388805277169), | |
148 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.679465575181126350155e-6), | |
149 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.285225331782217055858e-7), | |
150 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.681149956853776992068e-9) | |
151 | }; | |
152 | static const T Q[] = { | |
153 | BOOST_MATH_BIG_CONSTANT(T, 64, 1.0), | |
154 | BOOST_MATH_BIG_CONSTANT(T, 64, 3.46625407242567245975), | |
155 | BOOST_MATH_BIG_CONSTANT(T, 64, 5.38168345707006855425), | |
156 | BOOST_MATH_BIG_CONSTANT(T, 64, 4.77846592945843778382), | |
157 | BOOST_MATH_BIG_CONSTANT(T, 64, 2.59301921623620271374), | |
158 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.848854343457902036425), | |
159 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.152264338295331783612), | |
160 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.01105924229346489121) | |
161 | }; | |
162 | T xs = x - 1.125f; | |
163 | T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs); | |
164 | result = Y * x + R * x; | |
165 | } | |
166 | else if(x < 6) | |
167 | { | |
168 | // Max error found: 8.389174e-21 | |
169 | static const float Y = 0.93995571136474609375f; | |
170 | static const T P[] = { | |
171 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.0350353787183177984712), | |
172 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.00222426529213447927281), | |
173 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.0185573306514231072324), | |
174 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.00950804701325919603619), | |
175 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.00187123492819559223345), | |
176 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.000157544617424960554631), | |
177 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.460469890584317994083e-5), | |
178 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.230404776911882601748e-9), | |
179 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.266339227425782031962e-11) | |
180 | }; | |
181 | static const T Q[] = { | |
182 | BOOST_MATH_BIG_CONSTANT(T, 64, 1.0), | |
183 | BOOST_MATH_BIG_CONSTANT(T, 64, 1.3653349817554063097), | |
184 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.762059164553623404043), | |
185 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.220091105764131249824), | |
186 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.0341589143670947727934), | |
187 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.00263861676657015992959), | |
188 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.764675292302794483503e-4) | |
189 | }; | |
190 | T xs = x - 3; | |
191 | T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs); | |
192 | result = Y * x + R * x; | |
193 | } | |
194 | else if(x < 18) | |
195 | { | |
196 | // Max error found: 1.481312e-19 | |
197 | static const float Y = 0.98362827301025390625f; | |
198 | static const T P[] = { | |
199 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.0167431005076633737133), | |
200 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.00112951438745580278863), | |
201 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.00105628862152492910091), | |
202 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.000209386317487588078668), | |
203 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.149624783758342370182e-4), | |
204 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.449696789927706453732e-6), | |
205 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.462596163522878599135e-8), | |
206 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.281128735628831791805e-13), | |
207 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.99055709973310326855e-16) | |
208 | }; | |
209 | static const T Q[] = { | |
210 | BOOST_MATH_BIG_CONSTANT(T, 64, 1.0), | |
211 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.591429344886417493481), | |
212 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.138151865749083321638), | |
213 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.0160746087093676504695), | |
214 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.000964011807005165528527), | |
215 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.275335474764726041141e-4), | |
216 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.282243172016108031869e-6) | |
217 | }; | |
218 | T xs = x - 6; | |
219 | T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs); | |
220 | result = Y * x + R * x; | |
221 | } | |
222 | else if(x < 44) | |
223 | { | |
224 | // Max error found: 5.697761e-20 | |
225 | static const float Y = 0.99714565277099609375f; | |
226 | static const T P[] = { | |
227 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.0024978212791898131227), | |
228 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.779190719229053954292e-5), | |
229 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.254723037413027451751e-4), | |
230 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.162397777342510920873e-5), | |
231 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.396341011304801168516e-7), | |
232 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.411632831190944208473e-9), | |
233 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.145596286718675035587e-11), | |
234 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.116765012397184275695e-17) | |
235 | }; | |
236 | static const T Q[] = { | |
237 | BOOST_MATH_BIG_CONSTANT(T, 64, 1.0), | |
238 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.207123112214422517181), | |
239 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.0169410838120975906478), | |
240 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.000690538265622684595676), | |
241 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.145007359818232637924e-4), | |
242 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.144437756628144157666e-6), | |
243 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.509761276599778486139e-9) | |
244 | }; | |
245 | T xs = x - 18; | |
246 | T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs); | |
247 | result = Y * x + R * x; | |
248 | } | |
249 | else | |
250 | { | |
251 | // Max error found: 1.279746e-20 | |
252 | static const float Y = 0.99941349029541015625f; | |
253 | static const T P[] = { | |
254 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.000539042911019078575891), | |
255 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.28398759004727721098e-6), | |
256 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.899465114892291446442e-6), | |
257 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.229345859265920864296e-7), | |
258 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.225561444863500149219e-9), | |
259 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.947846627503022684216e-12), | |
260 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.135880130108924861008e-14), | |
261 | BOOST_MATH_BIG_CONSTANT(T, 64, -0.348890393399948882918e-21) | |
262 | }; | |
263 | static const T Q[] = { | |
264 | BOOST_MATH_BIG_CONSTANT(T, 64, 1.0), | |
265 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.0845746234001899436914), | |
266 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.00282092984726264681981), | |
267 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.468292921940894236786e-4), | |
268 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.399968812193862100054e-6), | |
269 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.161809290887904476097e-8), | |
270 | BOOST_MATH_BIG_CONSTANT(T, 64, 0.231558608310259605225e-11) | |
271 | }; | |
272 | T xs = x - 44; | |
273 | T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs); | |
274 | result = Y * x + R * x; | |
275 | } | |
276 | } | |
277 | return result; | |
278 | } | |
279 | ||
280 | template <class T, class Policy> | |
281 | struct erf_roots | |
282 | { | |
283 | boost::math::tuple<T,T,T> operator()(const T& guess) | |
284 | { | |
285 | BOOST_MATH_STD_USING | |
286 | T derivative = sign * (2 / sqrt(constants::pi<T>())) * exp(-(guess * guess)); | |
287 | T derivative2 = -2 * guess * derivative; | |
288 | return boost::math::make_tuple(((sign > 0) ? static_cast<T>(boost::math::erf(guess, Policy()) - target) : static_cast<T>(boost::math::erfc(guess, Policy())) - target), derivative, derivative2); | |
289 | } | |
290 | erf_roots(T z, int s) : target(z), sign(s) {} | |
291 | private: | |
292 | T target; | |
293 | int sign; | |
294 | }; | |
295 | ||
296 | template <class T, class Policy> | |
297 | T erf_inv_imp(const T& p, const T& q, const Policy& pol, const boost::mpl::int_<0>*) | |
298 | { | |
299 | // | |
300 | // Generic version, get a guess that's accurate to 64-bits (10^-19) | |
301 | // | |
302 | T guess = erf_inv_imp(p, q, pol, static_cast<mpl::int_<64> const*>(0)); | |
303 | T result; | |
304 | // | |
305 | // If T has more bit's than 64 in it's mantissa then we need to iterate, | |
306 | // otherwise we can just return the result: | |
307 | // | |
308 | if(policies::digits<T, Policy>() > 64) | |
309 | { | |
310 | boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>(); | |
311 | if(p <= 0.5) | |
312 | { | |
313 | result = tools::halley_iterate(detail::erf_roots<typename remove_cv<T>::type, Policy>(p, 1), guess, static_cast<T>(0), tools::max_value<T>(), (policies::digits<T, Policy>() * 2) / 3, max_iter); | |
314 | } | |
315 | else | |
316 | { | |
317 | result = tools::halley_iterate(detail::erf_roots<typename remove_cv<T>::type, Policy>(q, -1), guess, static_cast<T>(0), tools::max_value<T>(), (policies::digits<T, Policy>() * 2) / 3, max_iter); | |
318 | } | |
319 | policies::check_root_iterations<T>("boost::math::erf_inv<%1%>", max_iter, pol); | |
320 | } | |
321 | else | |
322 | { | |
323 | result = guess; | |
324 | } | |
325 | return result; | |
326 | } | |
327 | ||
328 | template <class T, class Policy> | |
329 | struct erf_inv_initializer | |
330 | { | |
331 | struct init | |
332 | { | |
333 | init() | |
334 | { | |
335 | do_init(); | |
336 | } | |
337 | static bool is_value_non_zero(T); | |
338 | static void do_init() | |
339 | { | |
340 | // If std::numeric_limits<T>::digits is zero, we must not call | |
341 | // our inituialization code here as the precision presumably | |
342 | // varies at runtime, and will not have been set yet. | |
343 | if(std::numeric_limits<T>::digits) | |
344 | { | |
345 | boost::math::erf_inv(static_cast<T>(0.25), Policy()); | |
346 | boost::math::erf_inv(static_cast<T>(0.55), Policy()); | |
347 | boost::math::erf_inv(static_cast<T>(0.95), Policy()); | |
348 | boost::math::erfc_inv(static_cast<T>(1e-15), Policy()); | |
349 | // These following initializations must not be called if | |
350 | // type T can not hold the relevant values without | |
351 | // underflow to zero. We check this at runtime because | |
352 | // some tools such as valgrind silently change the precision | |
353 | // of T at runtime, and numeric_limits basically lies! | |
354 | if(is_value_non_zero(static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1e-130)))) | |
355 | boost::math::erfc_inv(static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1e-130)), Policy()); | |
356 | ||
357 | // Some compilers choke on constants that would underflow, even in code that isn't instantiated | |
358 | // so try and filter these cases out in the preprocessor: | |
359 | #if LDBL_MAX_10_EXP >= 800 | |
360 | if(is_value_non_zero(static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1e-800)))) | |
361 | boost::math::erfc_inv(static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1e-800)), Policy()); | |
362 | if(is_value_non_zero(static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1e-900)))) | |
363 | boost::math::erfc_inv(static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1e-900)), Policy()); | |
364 | #else | |
365 | if(is_value_non_zero(static_cast<T>(BOOST_MATH_HUGE_CONSTANT(T, 64, 1e-800)))) | |
366 | boost::math::erfc_inv(static_cast<T>(BOOST_MATH_HUGE_CONSTANT(T, 64, 1e-800)), Policy()); | |
367 | if(is_value_non_zero(static_cast<T>(BOOST_MATH_HUGE_CONSTANT(T, 64, 1e-900)))) | |
368 | boost::math::erfc_inv(static_cast<T>(BOOST_MATH_HUGE_CONSTANT(T, 64, 1e-900)), Policy()); | |
369 | #endif | |
370 | } | |
371 | } | |
372 | void force_instantiate()const{} | |
373 | }; | |
374 | static const init initializer; | |
375 | static void force_instantiate() | |
376 | { | |
377 | initializer.force_instantiate(); | |
378 | } | |
379 | }; | |
380 | ||
381 | template <class T, class Policy> | |
382 | const typename erf_inv_initializer<T, Policy>::init erf_inv_initializer<T, Policy>::initializer; | |
383 | ||
384 | template <class T, class Policy> | |
385 | bool erf_inv_initializer<T, Policy>::init::is_value_non_zero(T v) | |
386 | { | |
387 | // This needs to be non-inline to detect whether v is non zero at runtime | |
388 | // rather than at compile time, only relevant when running under valgrind | |
389 | // which changes long double's to double's on the fly. | |
390 | return v != 0; | |
391 | } | |
392 | ||
393 | } // namespace detail | |
394 | ||
395 | template <class T, class Policy> | |
396 | typename tools::promote_args<T>::type erfc_inv(T z, const Policy& pol) | |
397 | { | |
398 | typedef typename tools::promote_args<T>::type result_type; | |
399 | ||
400 | // | |
401 | // Begin by testing for domain errors, and other special cases: | |
402 | // | |
403 | static const char* function = "boost::math::erfc_inv<%1%>(%1%, %1%)"; | |
404 | if((z < 0) || (z > 2)) | |
405 | return policies::raise_domain_error<result_type>(function, "Argument outside range [0,2] in inverse erfc function (got p=%1%).", z, pol); | |
406 | if(z == 0) | |
407 | return policies::raise_overflow_error<result_type>(function, 0, pol); | |
408 | if(z == 2) | |
409 | return -policies::raise_overflow_error<result_type>(function, 0, pol); | |
410 | // | |
411 | // Normalise the input, so it's in the range [0,1], we will | |
412 | // negate the result if z is outside that range. This is a simple | |
413 | // application of the erfc reflection formula: erfc(-z) = 2 - erfc(z) | |
414 | // | |
415 | result_type p, q, s; | |
416 | if(z > 1) | |
417 | { | |
418 | q = 2 - z; | |
419 | p = 1 - q; | |
420 | s = -1; | |
421 | } | |
422 | else | |
423 | { | |
424 | p = 1 - z; | |
425 | q = z; | |
426 | s = 1; | |
427 | } | |
428 | // | |
429 | // A bit of meta-programming to figure out which implementation | |
430 | // to use, based on the number of bits in the mantissa of T: | |
431 | // | |
432 | typedef typename policies::precision<result_type, Policy>::type precision_type; | |
433 | typedef typename mpl::if_< | |
434 | mpl::or_<mpl::less_equal<precision_type, mpl::int_<0> >, mpl::greater<precision_type, mpl::int_<64> > >, | |
435 | mpl::int_<0>, | |
436 | mpl::int_<64> | |
437 | >::type tag_type; | |
438 | // | |
439 | // Likewise use internal promotion, so we evaluate at a higher | |
440 | // precision internally if it's appropriate: | |
441 | // | |
442 | typedef typename policies::evaluation<result_type, Policy>::type eval_type; | |
443 | typedef typename policies::normalise< | |
444 | Policy, | |
445 | policies::promote_float<false>, | |
446 | policies::promote_double<false>, | |
447 | policies::discrete_quantile<>, | |
448 | policies::assert_undefined<> >::type forwarding_policy; | |
449 | ||
450 | detail::erf_inv_initializer<eval_type, forwarding_policy>::force_instantiate(); | |
451 | ||
452 | // | |
453 | // And get the result, negating where required: | |
454 | // | |
455 | return s * policies::checked_narrowing_cast<result_type, forwarding_policy>( | |
456 | detail::erf_inv_imp(static_cast<eval_type>(p), static_cast<eval_type>(q), forwarding_policy(), static_cast<tag_type const*>(0)), function); | |
457 | } | |
458 | ||
459 | template <class T, class Policy> | |
460 | typename tools::promote_args<T>::type erf_inv(T z, const Policy& pol) | |
461 | { | |
462 | typedef typename tools::promote_args<T>::type result_type; | |
463 | ||
464 | // | |
465 | // Begin by testing for domain errors, and other special cases: | |
466 | // | |
467 | static const char* function = "boost::math::erf_inv<%1%>(%1%, %1%)"; | |
468 | if((z < -1) || (z > 1)) | |
469 | return policies::raise_domain_error<result_type>(function, "Argument outside range [-1, 1] in inverse erf function (got p=%1%).", z, pol); | |
470 | if(z == 1) | |
471 | return policies::raise_overflow_error<result_type>(function, 0, pol); | |
472 | if(z == -1) | |
473 | return -policies::raise_overflow_error<result_type>(function, 0, pol); | |
474 | if(z == 0) | |
475 | return 0; | |
476 | // | |
477 | // Normalise the input, so it's in the range [0,1], we will | |
478 | // negate the result if z is outside that range. This is a simple | |
479 | // application of the erf reflection formula: erf(-z) = -erf(z) | |
480 | // | |
481 | result_type p, q, s; | |
482 | if(z < 0) | |
483 | { | |
484 | p = -z; | |
485 | q = 1 - p; | |
486 | s = -1; | |
487 | } | |
488 | else | |
489 | { | |
490 | p = z; | |
491 | q = 1 - z; | |
492 | s = 1; | |
493 | } | |
494 | // | |
495 | // A bit of meta-programming to figure out which implementation | |
496 | // to use, based on the number of bits in the mantissa of T: | |
497 | // | |
498 | typedef typename policies::precision<result_type, Policy>::type precision_type; | |
499 | typedef typename mpl::if_< | |
500 | mpl::or_<mpl::less_equal<precision_type, mpl::int_<0> >, mpl::greater<precision_type, mpl::int_<64> > >, | |
501 | mpl::int_<0>, | |
502 | mpl::int_<64> | |
503 | >::type tag_type; | |
504 | // | |
505 | // Likewise use internal promotion, so we evaluate at a higher | |
506 | // precision internally if it's appropriate: | |
507 | // | |
508 | typedef typename policies::evaluation<result_type, Policy>::type eval_type; | |
509 | typedef typename policies::normalise< | |
510 | Policy, | |
511 | policies::promote_float<false>, | |
512 | policies::promote_double<false>, | |
513 | policies::discrete_quantile<>, | |
514 | policies::assert_undefined<> >::type forwarding_policy; | |
515 | // | |
516 | // Likewise use internal promotion, so we evaluate at a higher | |
517 | // precision internally if it's appropriate: | |
518 | // | |
519 | typedef typename policies::evaluation<result_type, Policy>::type eval_type; | |
520 | ||
521 | detail::erf_inv_initializer<eval_type, forwarding_policy>::force_instantiate(); | |
522 | // | |
523 | // And get the result, negating where required: | |
524 | // | |
525 | return s * policies::checked_narrowing_cast<result_type, forwarding_policy>( | |
526 | detail::erf_inv_imp(static_cast<eval_type>(p), static_cast<eval_type>(q), forwarding_policy(), static_cast<tag_type const*>(0)), function); | |
527 | } | |
528 | ||
529 | template <class T> | |
530 | inline typename tools::promote_args<T>::type erfc_inv(T z) | |
531 | { | |
532 | return erfc_inv(z, policies::policy<>()); | |
533 | } | |
534 | ||
535 | template <class T> | |
536 | inline typename tools::promote_args<T>::type erf_inv(T z) | |
537 | { | |
538 | return erf_inv(z, policies::policy<>()); | |
539 | } | |
540 | ||
541 | } // namespace math | |
542 | } // namespace boost | |
543 | ||
544 | #ifdef _MSC_VER | |
545 | #pragma warning(pop) | |
546 | #endif | |
547 | ||
548 | #endif // BOOST_MATH_SF_ERF_INV_HPP | |
549 |