1 | // Copyright John Maddock 2008. |
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_DISTIBUTIONS_DETAIL_GENERIC_QUANTILE_HPP |
7 | #define BOOST_MATH_DISTIBUTIONS_DETAIL_GENERIC_QUANTILE_HPP |
8 | |
9 | namespace boost{ namespace math{ namespace detail{ |
10 | |
11 | template <class Dist> |
12 | struct generic_quantile_finder |
13 | { |
14 | typedef typename Dist::value_type value_type; |
15 | typedef typename Dist::policy_type policy_type; |
16 | |
17 | generic_quantile_finder(const Dist& d, value_type t, bool c) |
18 | : dist(d), target(t), comp(c) {} |
19 | |
20 | value_type operator()(const value_type& x) |
21 | { |
22 | return comp ? |
23 | value_type(target - cdf(complement(dist, x))) |
24 | : value_type(cdf(dist, x) - target); |
25 | } |
26 | |
27 | private: |
28 | Dist dist; |
29 | value_type target; |
30 | bool comp; |
31 | }; |
32 | |
33 | template <class T, class Policy> |
34 | inline T check_range_result(const T& x, const Policy& pol, const char* function) |
35 | { |
36 | if((x >= 0) && (x < tools::min_value<T>())) |
37 | return policies::raise_underflow_error<T>(function, 0, pol); |
38 | if(x <= -tools::max_value<T>()) |
39 | return -policies::raise_overflow_error<T>(function, 0, pol); |
40 | if(x >= tools::max_value<T>()) |
41 | return policies::raise_overflow_error<T>(function, 0, pol); |
42 | return x; |
43 | } |
44 | |
45 | template <class Dist> |
46 | typename Dist::value_type generic_quantile(const Dist& dist, const typename Dist::value_type& p, const typename Dist::value_type& guess, bool comp, const char* function) |
47 | { |
48 | typedef typename Dist::value_type value_type; |
49 | typedef typename Dist::policy_type policy_type; |
50 | typedef typename policies::normalise< |
51 | policy_type, |
52 | policies::promote_float<false>, |
53 | policies::promote_double<false>, |
54 | policies::discrete_quantile<>, |
55 | policies::assert_undefined<> >::type forwarding_policy; |
56 | |
57 | // |
58 | // Special cases first: |
59 | // |
60 | if(p == 0) |
61 | { |
62 | return comp |
63 | ? check_range_result(range(dist).second, forwarding_policy(), function) |
64 | : check_range_result(range(dist).first, forwarding_policy(), function); |
65 | } |
66 | if(p == 1) |
67 | { |
68 | return !comp |
69 | ? check_range_result(range(dist).second, forwarding_policy(), function) |
70 | : check_range_result(range(dist).first, forwarding_policy(), function); |
71 | } |
72 | |
73 | generic_quantile_finder<Dist> f(dist, p, comp); |
74 | tools::eps_tolerance<value_type> tol(policies::digits<value_type, forwarding_policy>() - 3); |
75 | boost::uintmax_t max_iter = policies::get_max_root_iterations<forwarding_policy>(); |
76 | std::pair<value_type, value_type> ir = tools::bracket_and_solve_root( |
77 | f, guess, value_type(2), true, tol, max_iter, forwarding_policy()); |
78 | value_type result = ir.first + (ir.second - ir.first) / 2; |
79 | if(max_iter >= policies::get_max_root_iterations<forwarding_policy>()) |
80 | { |
81 | return policies::raise_evaluation_error<value_type>(function, "Unable to locate solution in a reasonable time:" |
82 | " either there is no answer to quantile" |
83 | " or the answer is infinite. Current best guess is %1%" , result, forwarding_policy()); |
84 | } |
85 | return result; |
86 | } |
87 | |
88 | }}} // namespaces |
89 | |
90 | #endif // BOOST_MATH_DISTIBUTIONS_DETAIL_GENERIC_QUANTILE_HPP |
91 | |
92 | |