]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/math/test/test_roots.cpp
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)
8 #define BOOST_TEST_MAIN
9 #include <boost/test/unit_test.hpp>
10 #include <boost/test/floating_point_comparison.hpp>
11 #include <boost/test/results_collector.hpp>
12 #include <boost/math/special_functions/beta.hpp>
13 #include <boost/math/tools/roots.hpp>
14 #include <boost/test/results_collector.hpp>
15 #include <boost/test/unit_test.hpp>
16 #include <boost/array.hpp>
17 #include "table_type.hpp"
21 #define BOOST_CHECK_CLOSE_EX(a, b, prec, i) \
23 unsigned int failures = boost::unit_test::results_collector.results( boost::unit_test::framework::current_test_case().p_id ).p_assertions_failed;\
24 BOOST_CHECK_CLOSE(a, b, prec); \
25 if(failures != boost::unit_test::results_collector.results( boost::unit_test::framework::current_test_case().p_id ).p_assertions_failed)\
27 std::cerr << "Failure was at row " << i << std::endl;\
28 std::cerr << std::setprecision(35); \
29 std::cerr << "{ " << data[i][0] << " , " << data[i][1] << " , " << data[i][2];\
30 std::cerr << " , " << data[i][3] << " , " << data[i][4] << " , " << data[i][5] << " } " << std::endl;\
36 // Implement various versions of inverse of the incomplete beta
37 // using different root finding algorithms, and deliberately "bad"
38 // starting conditions: that way we get all the pathological cases
39 // we could ever wish for!!!
42 template <class T
, class Policy
>
43 struct ibeta_roots_1
// for first order algorithms
45 ibeta_roots_1(T _a
, T _b
, T t
, bool inv
= false)
46 : a(_a
), b(_b
), target(t
), invert(inv
) {}
48 T
operator()(const T
& x
)
50 return boost::math::detail::ibeta_imp(a
, b
, x
, Policy(), invert
, true) - target
;
57 template <class T
, class Policy
>
58 struct ibeta_roots_2
// for second order algorithms
60 ibeta_roots_2(T _a
, T _b
, T t
, bool inv
= false)
61 : a(_a
), b(_b
), target(t
), invert(inv
) {}
63 boost::math::tuple
<T
, T
> operator()(const T
& x
)
65 typedef typename
boost::math::lanczos::lanczos
<T
, Policy
>::type L
;
66 T f
= boost::math::detail::ibeta_imp(a
, b
, x
, Policy(), invert
, true) - target
;
68 -boost::math::detail::ibeta_power_terms(b
, a
, 1 - x
, x
, L(), true, Policy())
69 : boost::math::detail::ibeta_power_terms(a
, b
, x
, 1 - x
, L(), true, Policy());
72 y
= boost::math::tools::min_value
<T
>() * 8;
75 // make sure we don't have a zero derivative:
77 f1
= (invert
? -1 : 1) * boost::math::tools::min_value
<T
>() * 64;
79 return boost::math::make_tuple(f
, f1
);
86 template <class T
, class Policy
>
87 struct ibeta_roots_3
// for third order algorithms
89 ibeta_roots_3(T _a
, T _b
, T t
, bool inv
= false)
90 : a(_a
), b(_b
), target(t
), invert(inv
) {}
92 boost::math::tuple
<T
, T
, T
> operator()(const T
& x
)
94 typedef typename
boost::math::lanczos::lanczos
<T
, Policy
>::type L
;
95 T f
= boost::math::detail::ibeta_imp(a
, b
, x
, Policy(), invert
, true) - target
;
97 -boost::math::detail::ibeta_power_terms(b
, a
, 1 - x
, x
, L(), true, Policy())
98 : boost::math::detail::ibeta_power_terms(a
, b
, x
, 1 - x
, L(), true, Policy());
101 y
= boost::math::tools::min_value
<T
>() * 8;
103 T f2
= f1
* (-y
* a
+ (b
- 2) * x
+ 1) / (y
* x
);
107 // make sure we don't have a zero derivative:
109 f1
= (invert
? -1 : 1) * boost::math::tools::min_value
<T
>() * 64;
111 return boost::math::make_tuple(f
, f1
, f2
);
118 double inverse_ibeta_bisect(double a
, double b
, double z
)
120 typedef boost::math::policies::policy
<> pol
;
122 int bits
= std::numeric_limits
<double>::digits
;
125 // special cases, we need to have these because there may be other
132 // We need a good estimate of the error in the incomplete beta function
133 // so that we don't set the desired precision too high. Assume that 3-bits
134 // are lost each time the arguments increase by a factor of 10:
137 int bits_lost
= static_cast<int>(ceil(log10((std::max
)(a
, b
)) * 3));
142 int precision
= bits
- bits_lost
;
146 boost::math::tools::eps_tolerance
<double> tol(precision
);
147 return boost::math::tools::bisect(ibeta_roots_1
<double, pol
>(a
, b
, z
, invert
), min
, max
, tol
).first
;
150 double inverse_ibeta_newton(double a
, double b
, double z
)
154 int bits
= std::numeric_limits
<double>::digits
;
157 // special cases, we need to have these because there may be other
164 // We need a good estimate of the error in the incomplete beta function
165 // so that we don't set the desired precision too high. Assume that 3-bits
166 // are lost each time the arguments increase by a factor of 10:
169 int bits_lost
= static_cast<int>(ceil(log10((std::max
)(a
, b
)) * 3));
174 int precision
= bits
- bits_lost
;
178 return boost::math::tools::newton_raphson_iterate(ibeta_roots_2
<double, boost::math::policies::policy
<> >(a
, b
, z
, invert
), guess
, min
, max
, precision
);
181 double inverse_ibeta_halley(double a
, double b
, double z
)
185 int bits
= std::numeric_limits
<double>::digits
;
188 // special cases, we need to have these because there may be other
195 // We need a good estimate of the error in the incomplete beta function
196 // so that we don't set the desired precision too high. Assume that 3-bits
197 // are lost each time the arguments increase by a factor of 10:
200 int bits_lost
= static_cast<int>(ceil(log10((std::max
)(a
, b
)) * 3));
205 int precision
= bits
- bits_lost
;
209 return boost::math::tools::halley_iterate(ibeta_roots_3
<double, boost::math::policies::policy
<> >(a
, b
, z
, invert
), guess
, min
, max
, precision
);
212 double inverse_ibeta_schroder(double a
, double b
, double z
)
216 int bits
= std::numeric_limits
<double>::digits
;
219 // special cases, we need to have these because there may be other
226 // We need a good estimate of the error in the incomplete beta function
227 // so that we don't set the desired precision too high. Assume that 3-bits
228 // are lost each time the arguments increase by a factor of 10:
231 int bits_lost
= static_cast<int>(ceil(log10((std::max
)(a
, b
)) * 3));
236 int precision
= bits
- bits_lost
;
240 return boost::math::tools::schroder_iterate(ibeta_roots_3
<double, boost::math::policies::policy
<> >(a
, b
, z
, invert
), guess
, min
, max
, precision
);
244 template <class Real
, class T
>
245 void test_inverses(const T
& data
)
248 typedef Real value_type
;
250 value_type precision
= static_cast<value_type
>(ldexp(1.0, 1-boost::math::policies::digits
<value_type
, boost::math::policies::policy
<> >()/2)) * 150;
251 if(boost::math::policies::digits
<value_type
, boost::math::policies::policy
<> >() < 50)
252 precision
= 1; // 1% or two decimal digits, all we can hope for when the input is truncated
254 for(unsigned i
= 0; i
< data
.size(); ++i
)
257 // These inverse tests are thrown off if the output of the
258 // incomplete beta is too close to 1: basically there is insuffient
259 // information left in the value we're using as input to the inverse
260 // to be able to get back to the original value.
264 BOOST_CHECK_EQUAL(inverse_ibeta_halley(Real(data
[i
][0]), Real(data
[i
][1]), Real(data
[i
][5])), value_type(0));
265 BOOST_CHECK_EQUAL(inverse_ibeta_schroder(Real(data
[i
][0]), Real(data
[i
][1]), Real(data
[i
][5])), value_type(0));
266 BOOST_CHECK_EQUAL(inverse_ibeta_newton(Real(data
[i
][0]), Real(data
[i
][1]), Real(data
[i
][5])), value_type(0));
267 BOOST_CHECK_EQUAL(inverse_ibeta_bisect(Real(data
[i
][0]), Real(data
[i
][1]), Real(data
[i
][5])), value_type(0));
269 else if((1 - data
[i
][5] > 0.001)
270 && (fabs(data
[i
][5]) > 2 * boost::math::tools::min_value
<value_type
>())
271 && (fabs(data
[i
][5]) > 2 * boost::math::tools::min_value
<double>()))
273 value_type inv
= inverse_ibeta_halley(Real(data
[i
][0]), Real(data
[i
][1]), Real(data
[i
][5]));
274 BOOST_CHECK_CLOSE_EX(Real(data
[i
][2]), inv
, precision
, i
);
275 inv
= inverse_ibeta_schroder(Real(data
[i
][0]), Real(data
[i
][1]), Real(data
[i
][5]));
276 BOOST_CHECK_CLOSE_EX(Real(data
[i
][2]), inv
, precision
, i
);
277 inv
= inverse_ibeta_newton(Real(data
[i
][0]), Real(data
[i
][1]), Real(data
[i
][5]));
278 BOOST_CHECK_CLOSE_EX(Real(data
[i
][2]), inv
, precision
, i
);
279 inv
= inverse_ibeta_bisect(Real(data
[i
][0]), Real(data
[i
][1]), Real(data
[i
][5]));
280 BOOST_CHECK_CLOSE_EX(Real(data
[i
][2]), inv
, precision
, i
);
282 else if(1 == data
[i
][5])
284 BOOST_CHECK_EQUAL(inverse_ibeta_halley(Real(data
[i
][0]), Real(data
[i
][1]), Real(data
[i
][5])), value_type(1));
285 BOOST_CHECK_EQUAL(inverse_ibeta_schroder(Real(data
[i
][0]), Real(data
[i
][1]), Real(data
[i
][5])), value_type(1));
286 BOOST_CHECK_EQUAL(inverse_ibeta_newton(Real(data
[i
][0]), Real(data
[i
][1]), Real(data
[i
][5])), value_type(1));
287 BOOST_CHECK_EQUAL(inverse_ibeta_bisect(Real(data
[i
][0]), Real(data
[i
][1]), Real(data
[i
][5])), value_type(1));
294 #define SC_(x) static_cast<typename table_type<T>::type>(BOOST_JOIN(x, L))
298 void test_beta(T
, const char* /* name */)
301 // The actual test data is rather verbose, so it's in a separate file
303 // The contents are as follows, each row of data contains
304 // five items, input value a, input value b, integration limits x, beta(a, b, x) and ibeta(a, b, x):
306 # include "ibeta_small_data.ipp"
308 test_inverses
<T
>(ibeta_small_data
);
310 # include "ibeta_data.ipp"
312 test_inverses
<T
>(ibeta_data
);
314 # include "ibeta_large_data.ipp"
316 test_inverses
<T
>(ibeta_large_data
);
319 BOOST_AUTO_TEST_CASE( test_main
)
321 test_beta(0.1, "double");