Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / math / include_private / boost / math / tools / test.hpp
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_TOOLS_TEST_HPP
7 #define BOOST_MATH_TOOLS_TEST_HPP
8
9 #ifdef _MSC_VER
10 #pragma once
11 #endif
12
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>
19 #include <stdexcept>
20 #include <iostream>
21 #include <iomanip>
22
23 namespace boost{ namespace math{ namespace tools{
24
25 template <class T>
26 struct test_result
27 {
28 private:
29    boost::math::tools::stats<T> stat;   // Statistics for the test.
30    unsigned worst_case;                 // Index of the worst case test.
31 public:
32    test_result() { worst_case = 0; }
33    void set_worst(int i){ worst_case = i; }
34    void add(const T& point){ stat.add(point); }
35    // accessors:
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(); }
45
46    test_result& operator+=(const test_result& t)
47    {
48       if((t.stat.max)() > (stat.max)())
49          worst_case = t.worst_case;
50       stat += t.stat;
51       return *this;
52    }
53 };
54
55 template <class T>
56 struct calculate_result_type
57 {
58    typedef typename T::value_type row_type;
59    typedef typename row_type::value_type value_type;
60 };
61
62 template <class T>
63 T relative_error(T a, T b)
64 {
65    return boost::math::relative_difference(a, b);
66 }
67
68
69 template <class T>
70 void set_output_precision(T, std::ostream& os)
71 {
72 #ifdef BOOST_MSVC
73 #pragma warning(push)
74 #pragma warning(disable:4127)
75 #endif
76    if(std::numeric_limits<T>::digits10)
77    {
78       os << std::setprecision(std::numeric_limits<T>::digits10 + 2);
79    }
80 #ifdef BOOST_MSVC
81 #pragma warning(pop)
82 #endif
83 }
84
85 template <class Seq>
86 void print_row(const Seq& row, std::ostream& os = std::cout)
87 {
88    try {
89       set_output_precision(row[0], os);
90       for (unsigned i = 0; i < row.size(); ++i)
91       {
92          if (i)
93             os << ", ";
94          os << row[i];
95       }
96       os << std::endl;
97    }
98    catch (const std::exception&) {}
99 }
100
101 //
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
106 // expressions.
107 //
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)
110 {
111    typedef typename A::value_type         row_type;
112    typedef typename row_type::value_type  value_type;
113
114    test_result<value_type> result;
115
116    for(unsigned i = 0; i < a.size(); ++i)
117    {
118       const row_type& row = a[i];
119       value_type point;
120 #ifndef BOOST_NO_EXCEPTIONS
121       try
122       {
123 #endif
124          point = test_func(row);
125 #ifndef BOOST_NO_EXCEPTIONS
126       }
127       catch(const std::underflow_error&)
128       {
129          point = 0;
130       }
131       catch(const std::overflow_error&)
132       {
133          point = std::numeric_limits<value_type>::has_infinity ? 
134             std::numeric_limits<value_type>::infinity()
135             : tools::max_value<value_type>();
136       }
137       catch(const std::exception& e)
138       {
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);
144       }
145 #endif
146       value_type expected = expect_func(row);
147       value_type err = relative_error(point, expected);
148 #ifdef BOOST_INSTRUMENT
149       if(err != 0)
150       {
151          std::cout << row[0] << " " << err;
152          if(std::numeric_limits<value_type>::is_specialized)
153          {
154             std::cout << " (" << err / std::numeric_limits<value_type>::epsilon() << "eps)";
155          }
156          std::cout << std::endl;
157       }
158 #endif
159       if(!(boost::math::isfinite)(point) && (boost::math::isfinite)(expected))
160       {
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");
165       }
166       if(err > 0.5)
167       {
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");
172       }
173       result.add(err);
174       if((result.max)() == err)
175          result.set_worst(i);
176    }
177    return result;
178 }
179
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)
182 {
183    typedef typename A::value_type         row_type;
184    typedef Real                          value_type;
185
186    test_result<value_type> result;
187
188    for(unsigned i = 0; i < a.size(); ++i)
189    {
190       const row_type& row = a[i];
191       value_type point;
192 #ifndef BOOST_NO_EXCEPTIONS
193       try
194       {
195 #endif
196          point = test_func(row);
197 #ifndef BOOST_NO_EXCEPTIONS
198       }
199       catch(const std::underflow_error&)
200       {
201          point = 0;
202       }
203       catch(const std::overflow_error&)
204       {
205          point = std::numeric_limits<value_type>::has_infinity ? 
206             std::numeric_limits<value_type>::infinity()
207             : tools::max_value<value_type>();
208       }
209       catch(const std::exception& e)
210       {
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);
217       }
218 #endif
219       value_type expected = expect_func(row);
220       value_type err = relative_error(point, expected);
221 #ifdef BOOST_INSTRUMENT
222       if(err != 0)
223       {
224          std::cout << row[0] << " " << err;
225          if(std::numeric_limits<value_type>::is_specialized)
226          {
227             std::cout << " (" << err / std::numeric_limits<value_type>::epsilon() << "eps)";
228          }
229          std::cout << std::endl;
230       }
231 #endif
232       if(!(boost::math::isfinite)(point) && (boost::math::isfinite)(expected))
233       {
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");
238       }
239       if(err > 0.5)
240       {
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");
245       }
246       result.add(err);
247       if((result.max)() == err)
248          result.set_worst(i);
249    }
250    return result;
251 }
252
253 template <class Val, class Exception>
254 void test_check_throw(Val v, Exception e)
255 {
256    BOOST_CHECK(errno);
257    errno = 0;
258 }
259
260 template <class Val>
261 void test_check_throw(Val val, std::domain_error const* e)
262 {
263    BOOST_CHECK(errno == EDOM);
264    errno = 0;
265    if(std::numeric_limits<Val>::has_quiet_NaN)
266    {
267       BOOST_CHECK((boost::math::isnan)(val));
268    }
269 }
270
271 template <class Val>
272 void test_check_throw(Val v, std::overflow_error const* e)
273 {
274    BOOST_CHECK(errno == ERANGE);
275    errno = 0;
276    BOOST_CHECK((v >= boost::math::tools::max_value<Val>()) || (v <= -boost::math::tools::max_value<Val>()));
277 }
278
279 template <class Val>
280 void test_check_throw(Val v, boost::math::rounding_error const* e)
281 {
282    BOOST_CHECK(errno == ERANGE);
283    errno = 0;
284    if(std::numeric_limits<Val>::is_specialized && std::numeric_limits<Val>::is_integer)
285    {
286       BOOST_CHECK((v == (std::numeric_limits<Val>::max)()) || (v == (std::numeric_limits<Val>::min)()));
287    }
288    else
289    {
290       BOOST_CHECK((v == boost::math::tools::max_value<Val>()) || (v == -boost::math::tools::max_value<Val>()));
291    }
292 }
293
294 } // namespace tools
295 } // namespace math
296 } // namespace boost
297
298
299   //
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:
302   //
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));
305 #else
306 #  define BOOST_MATH_CHECK_THROW(x, y) BOOST_CHECK_THROW(x, y)
307 #endif
308
309 #endif
310
311