1 // Copyright John Maddock 2007.
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)
6 #ifndef BOOST_MATH_DISTRIBUTIONS_DETAIL_INV_DISCRETE_QUANTILE
7 #define BOOST_MATH_DISTRIBUTIONS_DETAIL_INV_DISCRETE_QUANTILE
11 namespace boost{ namespace math{ namespace detail{
14 // Functor for root finding algorithm:
17 struct distribution_quantile_finder
19 typedef typename Dist::value_type value_type;
20 typedef typename Dist::policy_type policy_type;
22 distribution_quantile_finder(const Dist d, value_type p, bool c)
23 : dist(d), target(p), comp(c) {}
25 value_type operator()(value_type const& x)
27 return comp ? value_type(target - cdf(complement(dist, x))) : value_type(cdf(dist, x) - target);
36 // The purpose of adjust_bounds, is to toggle the last bit of the
37 // range so that both ends round to the same integer, if possible.
38 // If they do both round the same then we terminate the search
39 // for the root *very* quickly when finding an integer result.
40 // At the point that this function is called we know that "a" is
41 // below the root and "b" above it, so this change can not result
42 // in the root no longer being bracketed.
44 template <class Real, class Tol>
45 void adjust_bounds(Real& /* a */, Real& /* b */, Tol const& /* tol */){}
48 void adjust_bounds(Real& /* a */, Real& b, tools::equal_floor const& /* tol */)
51 b -= tools::epsilon<Real>() * b;
55 void adjust_bounds(Real& a, Real& /* b */, tools::equal_ceil const& /* tol */)
58 a += tools::epsilon<Real>() * a;
62 void adjust_bounds(Real& a, Real& b, tools::equal_nearest_integer const& /* tol */)
65 a += tools::epsilon<Real>() * a;
66 b -= tools::epsilon<Real>() * b;
69 // This is where all the work is done:
71 template <class Dist, class Tolerance>
72 typename Dist::value_type
73 do_inverse_discrete_quantile(
75 const typename Dist::value_type& p,
77 typename Dist::value_type guess,
78 const typename Dist::value_type& multiplier,
79 typename Dist::value_type adder,
81 boost::uintmax_t& max_iter)
83 typedef typename Dist::value_type value_type;
84 typedef typename Dist::policy_type policy_type;
86 static const char* function = "boost::math::do_inverse_discrete_quantile<%1%>";
90 distribution_quantile_finder<Dist> f(dist, p, comp);
92 // Max bounds of the distribution:
94 value_type min_bound, max_bound;
95 boost::math::tie(min_bound, max_bound) = support(dist);
102 value_type fa = f(guess);
103 boost::uintmax_t count = max_iter - 1;
104 value_type fb(fa), a(guess), b =0; // Compiler warning C4701: potentially uninitialized local variable 'b' used
110 // For small expected results, just use a linear search:
115 while((a < 10) && (fa * fb >= 0))
128 return b; // can't go any higher!
133 a = (std::max)(value_type(b - 1), value_type(0));
141 return a; // We can't go any lower than this!
146 // Try and bracket using a couple of additions first,
147 // we're assuming that "guess" is likely to be accurate
148 // to the nearest int or so:
153 // If we're looking for a large result, then bump "adder" up
154 // by a bit to increase our chances of bracketing the root:
156 //adder = (std::max)(adder, 0.001f * guess);
165 b = (std::max)(value_type(a - adder), value_type(0));
173 if(count && (fa * fb >= 0))
176 // We didn't bracket the root, try
189 b = (std::max)(value_type(a - adder), value_type(0));
204 // If the root hasn't been bracketed yet, try again
205 // using the multiplier this time:
207 if((boost::math::sign)(fb) == (boost::math::sign)(fa))
212 // Zero is to the right of x2, so walk upwards
215 while(((boost::math::sign)(fb) == (boost::math::sign)(fa)) && (a != b))
218 return policies::raise_evaluation_error(function, "Unable to bracket root, last nearest value was %1%", b, policy_type());
226 BOOST_MATH_INSTRUMENT_CODE("a = " << a << " b = " << b << " fa = " << fa << " fb = " << fb << " count = " << count);
232 // Zero is to the left of a, so walk downwards
235 while(((boost::math::sign)(fb) == (boost::math::sign)(fa)) && (a != b))
237 if(fabs(a) < tools::min_value<value_type>())
239 // Escape route just in case the answer is zero!
245 return policies::raise_evaluation_error(function, "Unable to bracket root, last nearest value was %1%", a, policy_type());
253 BOOST_MATH_INSTRUMENT_CODE("a = " << a << " b = " << b << " fa = " << fa << " fb = " << fb << " count = " << count);
263 return b; // Ran out of bounds trying to bracket - there is no answer!
265 // Adjust bounds so that if we're looking for an integer
266 // result, then both ends round the same way:
268 adjust_bounds(a, b, tol);
270 // We don't want zero or denorm lower bounds:
272 if(a < tools::min_value<value_type>())
273 a = tools::min_value<value_type>();
275 // Go ahead and find the root:
277 std::pair<value_type, value_type> r = toms748_solve(f, a, b, fa, fb, tol, count, policy_type());
279 BOOST_MATH_INSTRUMENT_CODE("max_iter = " << max_iter << " count = " << count);
280 return (r.first + r.second) / 2;
283 // Some special routine for rounding up and down:
284 // We want to check and see if we are very close to an integer, and if so test to see if
285 // that integer is an exact root of the cdf. We do this because our root finder only
286 // guarantees to find *a root*, and there can sometimes be many consecutive floating
287 // point values which are all roots. This is especially true if the target probability
290 template <class Dist>
291 inline typename Dist::value_type round_to_floor(const Dist& d, typename Dist::value_type result, typename Dist::value_type p, bool c)
294 typename Dist::value_type cc = ceil(result);
295 typename Dist::value_type pp = cc <= support(d).second ? c ? cdf(complement(d, cc)) : cdf(d, cc) : 1;
299 result = floor(result);
301 // Now find the smallest integer <= result for which we get an exact root:
306 if(cc < support(d).first)
308 pp = c ? cdf(complement(d, cc)) : cdf(d, cc);
311 else if(c ? pp > p : pp < p)
320 #pragma warning(push)
321 #pragma warning(disable:4127)
324 template <class Dist>
325 inline typename Dist::value_type round_to_ceil(const Dist& d, typename Dist::value_type result, typename Dist::value_type p, bool c)
328 typename Dist::value_type cc = floor(result);
329 typename Dist::value_type pp = cc >= support(d).first ? c ? cdf(complement(d, cc)) : cdf(d, cc) : 0;
333 result = ceil(result);
335 // Now find the largest integer >= result for which we get an exact root:
340 if(cc > support(d).second)
342 pp = c ? cdf(complement(d, cc)) : cdf(d, cc);
345 else if(c ? pp < p : pp > p)
357 // Now finally are the public API functions.
358 // There is one overload for each policy,
359 // each one is responsible for selecting the correct
360 // termination condition, and rounding the result
361 // to an int where required.
363 template <class Dist>
364 inline typename Dist::value_type
365 inverse_discrete_quantile(
367 typename Dist::value_type p,
369 const typename Dist::value_type& guess,
370 const typename Dist::value_type& multiplier,
371 const typename Dist::value_type& adder,
372 const policies::discrete_quantile<policies::real>&,
373 boost::uintmax_t& max_iter)
380 typename Dist::value_type pp = c ? 1 - p : p;
381 if(pp <= pdf(dist, 0))
383 return do_inverse_discrete_quantile(
390 tools::eps_tolerance<typename Dist::value_type>(policies::digits<typename Dist::value_type, typename Dist::policy_type>()),
394 template <class Dist>
395 inline typename Dist::value_type
396 inverse_discrete_quantile(
398 const typename Dist::value_type& p,
400 const typename Dist::value_type& guess,
401 const typename Dist::value_type& multiplier,
402 const typename Dist::value_type& adder,
403 const policies::discrete_quantile<policies::integer_round_outwards>&,
404 boost::uintmax_t& max_iter)
406 typedef typename Dist::value_type value_type;
408 typename Dist::value_type pp = c ? 1 - p : p;
409 if(pp <= pdf(dist, 0))
412 // What happens next depends on whether we're looking for an
413 // upper or lower quantile:
416 return round_to_floor(dist, do_inverse_discrete_quantile(
420 (guess < 1 ? value_type(1) : (value_type)floor(guess)),
423 tools::equal_floor(),
426 return round_to_ceil(dist, do_inverse_discrete_quantile(
430 (value_type)ceil(guess),
437 template <class Dist>
438 inline typename Dist::value_type
439 inverse_discrete_quantile(
441 const typename Dist::value_type& p,
443 const typename Dist::value_type& guess,
444 const typename Dist::value_type& multiplier,
445 const typename Dist::value_type& adder,
446 const policies::discrete_quantile<policies::integer_round_inwards>&,
447 boost::uintmax_t& max_iter)
449 typedef typename Dist::value_type value_type;
451 typename Dist::value_type pp = c ? 1 - p : p;
452 if(pp <= pdf(dist, 0))
455 // What happens next depends on whether we're looking for an
456 // upper or lower quantile:
459 return round_to_ceil(dist, do_inverse_discrete_quantile(
469 return round_to_floor(dist, do_inverse_discrete_quantile(
473 (guess < 1 ? value_type(1) : floor(guess)),
476 tools::equal_floor(),
480 template <class Dist>
481 inline typename Dist::value_type
482 inverse_discrete_quantile(
484 const typename Dist::value_type& p,
486 const typename Dist::value_type& guess,
487 const typename Dist::value_type& multiplier,
488 const typename Dist::value_type& adder,
489 const policies::discrete_quantile<policies::integer_round_down>&,
490 boost::uintmax_t& max_iter)
492 typedef typename Dist::value_type value_type;
494 typename Dist::value_type pp = c ? 1 - p : p;
495 if(pp <= pdf(dist, 0))
497 return round_to_floor(dist, do_inverse_discrete_quantile(
501 (guess < 1 ? value_type(1) : floor(guess)),
504 tools::equal_floor(),
508 template <class Dist>
509 inline typename Dist::value_type
510 inverse_discrete_quantile(
512 const typename Dist::value_type& p,
514 const typename Dist::value_type& guess,
515 const typename Dist::value_type& multiplier,
516 const typename Dist::value_type& adder,
517 const policies::discrete_quantile<policies::integer_round_up>&,
518 boost::uintmax_t& max_iter)
521 typename Dist::value_type pp = c ? 1 - p : p;
522 if(pp <= pdf(dist, 0))
524 return round_to_ceil(dist, do_inverse_discrete_quantile(
535 template <class Dist>
536 inline typename Dist::value_type
537 inverse_discrete_quantile(
539 const typename Dist::value_type& p,
541 const typename Dist::value_type& guess,
542 const typename Dist::value_type& multiplier,
543 const typename Dist::value_type& adder,
544 const policies::discrete_quantile<policies::integer_round_nearest>&,
545 boost::uintmax_t& max_iter)
547 typedef typename Dist::value_type value_type;
549 typename Dist::value_type pp = c ? 1 - p : p;
550 if(pp <= pdf(dist, 0))
553 // Note that we adjust the guess to the nearest half-integer:
554 // this increase the chances that we will bracket the root
555 // with two results that both round to the same integer quickly.
557 return round_to_floor(dist, do_inverse_discrete_quantile(
561 (guess < 0.5f ? value_type(1.5f) : floor(guess + 0.5f) + 0.5f),
564 tools::equal_nearest_integer(),
565 max_iter) + 0.5f, p, c);
570 #endif // BOOST_MATH_DISTRIBUTIONS_DETAIL_INV_DISCRETE_QUANTILE