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)
6 #ifndef BOOST_MATH_TOOLS_TEST_HPP
7 #define BOOST_MATH_TOOLS_TEST_HPP
13 #include <boost/math/tools/config.hpp>
14 #include <boost/math/tools/stats.hpp>
15 #include <boost/math/special_functions/fpclassify.hpp>
16 #include <boost/math/special_functions/relative_difference.hpp>
17 #include <boost/math/policies/error_handling.hpp>
18 #include <boost/test/test_tools.hpp>
23 namespace boost{ namespace math{ namespace tools{
29 boost::math::tools::stats<T> stat; // Statistics for the test.
30 unsigned worst_case; // Index of the worst case test.
32 test_result() { worst_case = 0; }
33 void set_worst(int i){ worst_case = i; }
34 void add(const T& point){ stat.add(point); }
36 unsigned worst()const{ return worst_case; }
37 T min BOOST_PREVENT_MACRO_SUBSTITUTION()const{ return (stat.min)(); }
38 T max BOOST_PREVENT_MACRO_SUBSTITUTION()const{ return (stat.max)(); }
39 T total()const{ return stat.total(); }
40 T mean()const{ return stat.mean(); }
41 boost::uintmax_t count()const{ return stat.count(); }
42 T variance()const{ return stat.variance(); }
43 T variance1()const{ return stat.variance1(); }
44 T rms()const{ return stat.rms(); }
46 test_result& operator+=(const test_result& t)
48 if((t.stat.max)() > (stat.max)())
49 worst_case = t.worst_case;
56 struct calculate_result_type
58 typedef typename T::value_type row_type;
59 typedef typename row_type::value_type value_type;
63 T relative_error(T a, T b)
65 return boost::math::relative_difference(a, b);
70 void set_output_precision(T, std::ostream& os)
74 #pragma warning(disable:4127)
76 if(std::numeric_limits<T>::digits10)
78 os << std::setprecision(std::numeric_limits<T>::digits10 + 2);
86 void print_row(const Seq& row, std::ostream& os = std::cout)
89 set_output_precision(row[0], os);
90 for (unsigned i = 0; i < row.size(); ++i)
98 catch (const std::exception&) {}
102 // Function test accepts an matrix of input values (probably a 2D boost::array)
103 // and calls two functors for each row in the array - one calculates a value
104 // to test, and one extracts the expected value from the array (or possibly
105 // calculates it at high precision). The two functors are usually simple lambda
108 template <class A, class F1, class F2>
109 test_result<typename calculate_result_type<A>::value_type> test(const A& a, F1 test_func, F2 expect_func)
111 typedef typename A::value_type row_type;
112 typedef typename row_type::value_type value_type;
114 test_result<value_type> result;
116 for(unsigned i = 0; i < a.size(); ++i)
118 const row_type& row = a[i];
120 #ifndef BOOST_NO_EXCEPTIONS
124 point = test_func(row);
125 #ifndef BOOST_NO_EXCEPTIONS
127 catch(const std::underflow_error&)
131 catch(const std::overflow_error&)
133 point = std::numeric_limits<value_type>::has_infinity ?
134 std::numeric_limits<value_type>::infinity()
135 : tools::max_value<value_type>();
137 catch(const std::exception& e)
139 std::cerr << e.what() << std::endl;
140 print_row(row, std::cerr);
141 BOOST_ERROR("Unexpected exception.");
142 // so we don't get further errors:
143 point = expect_func(row);
146 value_type expected = expect_func(row);
147 value_type err = relative_error(point, expected);
148 #ifdef BOOST_INSTRUMENT
151 std::cout << row[0] << " " << err;
152 if(std::numeric_limits<value_type>::is_specialized)
154 std::cout << " (" << err / std::numeric_limits<value_type>::epsilon() << "eps)";
156 std::cout << std::endl;
159 if(!(boost::math::isfinite)(point) && (boost::math::isfinite)(expected))
161 std::cerr << "CAUTION: Found non-finite result, when a finite value was expected at entry " << i << "\n";
162 std::cerr << "Found: " << point << " Expected " << expected << " Error: " << err << std::endl;
163 print_row(row, std::cerr);
164 BOOST_ERROR("Unexpected non-finite result");
168 std::cerr << "CAUTION: Gross error found at entry " << i << ".\n";
169 std::cerr << "Found: " << point << " Expected " << expected << " Error: " << err << std::endl;
170 print_row(row, std::cerr);
171 BOOST_ERROR("Gross error");
174 if((result.max)() == err)
180 template <class Real, class A, class F1, class F2>
181 test_result<Real> test_hetero(const A& a, F1 test_func, F2 expect_func)
183 typedef typename A::value_type row_type;
184 typedef Real value_type;
186 test_result<value_type> result;
188 for(unsigned i = 0; i < a.size(); ++i)
190 const row_type& row = a[i];
192 #ifndef BOOST_NO_EXCEPTIONS
196 point = test_func(row);
197 #ifndef BOOST_NO_EXCEPTIONS
199 catch(const std::underflow_error&)
203 catch(const std::overflow_error&)
205 point = std::numeric_limits<value_type>::has_infinity ?
206 std::numeric_limits<value_type>::infinity()
207 : tools::max_value<value_type>();
209 catch(const std::exception& e)
211 std::cerr << "Unexpected exception at entry: " << i << "\n";
212 std::cerr << e.what() << std::endl;
213 print_row(row, std::cerr);
214 BOOST_ERROR("Unexpected exception.");
215 // so we don't get further errors:
216 point = expect_func(row);
219 value_type expected = expect_func(row);
220 value_type err = relative_error(point, expected);
221 #ifdef BOOST_INSTRUMENT
224 std::cout << row[0] << " " << err;
225 if(std::numeric_limits<value_type>::is_specialized)
227 std::cout << " (" << err / std::numeric_limits<value_type>::epsilon() << "eps)";
229 std::cout << std::endl;
232 if(!(boost::math::isfinite)(point) && (boost::math::isfinite)(expected))
234 std::cerr << "CAUTION: Found non-finite result, when a finite value was expected at entry " << i << "\n";
235 std::cerr << "Found: " << point << " Expected " << expected << " Error: " << err << std::endl;
236 print_row(row, std::cerr);
237 BOOST_ERROR("Unexpected non-finite result");
241 std::cerr << "CAUTION: Gross error found at entry " << i << ".\n";
242 std::cerr << "Found: " << point << " Expected " << expected << " Error: " << err << std::endl;
243 print_row(row, std::cerr);
244 BOOST_ERROR("Gross error");
247 if((result.max)() == err)
253 template <class Val, class Exception>
254 void test_check_throw(Val v, Exception e)
261 void test_check_throw(Val val, std::domain_error const* e)
263 BOOST_CHECK(errno == EDOM);
265 if(std::numeric_limits<Val>::has_quiet_NaN)
267 BOOST_CHECK((boost::math::isnan)(val));
272 void test_check_throw(Val v, std::overflow_error const* e)
274 BOOST_CHECK(errno == ERANGE);
276 BOOST_CHECK((v >= boost::math::tools::max_value<Val>()) || (v <= -boost::math::tools::max_value<Val>()));
280 void test_check_throw(Val v, boost::math::rounding_error const* e)
282 BOOST_CHECK(errno == ERANGE);
284 if(std::numeric_limits<Val>::is_specialized && std::numeric_limits<Val>::is_integer)
286 BOOST_CHECK((v == (std::numeric_limits<Val>::max)()) || (v == (std::numeric_limits<Val>::min)()));
290 BOOST_CHECK((v == boost::math::tools::max_value<Val>()) || (v == -boost::math::tools::max_value<Val>()));
300 // exception-free testing support, ideally we'd only define this in our tests,
301 // but to keep things simple we really need it somewhere that's always included:
303 #ifdef BOOST_NO_EXCEPTIONS
304 # define BOOST_MATH_CHECK_THROW(x, ExceptionType) boost::math::tools::test_check_throw(x, static_cast<ExceptionType const*>(0));
306 # define BOOST_MATH_CHECK_THROW(x, y) BOOST_CHECK_THROW(x, y)