]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/math/include_private/boost/math/tools/test.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / libs / math / include_private / boost / math / tools / test.hpp
CommitLineData
7c673cae
FG
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
23namespace boost{ namespace math{ namespace tools{
24
25template <class T>
26struct test_result
27{
28private:
29 boost::math::tools::stats<T> stat; // Statistics for the test.
30 unsigned worst_case; // Index of the worst case test.
31public:
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(); }
1e59de90 41 std::uintmax_t count()const{ return stat.count(); }
7c673cae
FG
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
55template <class T>
56struct calculate_result_type
57{
58 typedef typename T::value_type row_type;
59 typedef typename row_type::value_type value_type;
60};
61
62template <class T>
63T relative_error(T a, T b)
64{
65 return boost::math::relative_difference(a, b);
66}
67
68
69template <class T>
92f5a8d4 70void set_output_precision(T, std::ostream& os)
7c673cae 71{
1e59de90 72#ifdef _MSC_VER
7c673cae
FG
73#pragma warning(push)
74#pragma warning(disable:4127)
75#endif
76 if(std::numeric_limits<T>::digits10)
77 {
92f5a8d4 78 os << std::setprecision(std::numeric_limits<T>::digits10 + 2);
7c673cae 79 }
20effc67
TL
80 else
81 os << std::setprecision(22); // and hope for the best!
82
1e59de90 83#ifdef _MSC_VER
7c673cae
FG
84#pragma warning(pop)
85#endif
86}
87
88template <class Seq>
89void print_row(const Seq& row, std::ostream& os = std::cout)
90{
92f5a8d4
TL
91 try {
92 set_output_precision(row[0], os);
93 for (unsigned i = 0; i < row.size(); ++i)
94 {
95 if (i)
96 os << ", ";
97 os << row[i];
98 }
99 os << std::endl;
7c673cae 100 }
92f5a8d4 101 catch (const std::exception&) {}
7c673cae
FG
102}
103
104//
1e59de90 105// Function test accepts an matrix of input values (probably a 2D std::array)
7c673cae
FG
106// and calls two functors for each row in the array - one calculates a value
107// to test, and one extracts the expected value from the array (or possibly
108// calculates it at high precision). The two functors are usually simple lambda
109// expressions.
110//
111template <class A, class F1, class F2>
112test_result<typename calculate_result_type<A>::value_type> test(const A& a, F1 test_func, F2 expect_func)
113{
114 typedef typename A::value_type row_type;
115 typedef typename row_type::value_type value_type;
116
117 test_result<value_type> result;
118
119 for(unsigned i = 0; i < a.size(); ++i)
120 {
121 const row_type& row = a[i];
122 value_type point;
123#ifndef BOOST_NO_EXCEPTIONS
124 try
125 {
126#endif
127 point = test_func(row);
128#ifndef BOOST_NO_EXCEPTIONS
129 }
130 catch(const std::underflow_error&)
131 {
132 point = 0;
133 }
134 catch(const std::overflow_error&)
135 {
136 point = std::numeric_limits<value_type>::has_infinity ?
137 std::numeric_limits<value_type>::infinity()
138 : tools::max_value<value_type>();
139 }
140 catch(const std::exception& e)
141 {
142 std::cerr << e.what() << std::endl;
143 print_row(row, std::cerr);
144 BOOST_ERROR("Unexpected exception.");
145 // so we don't get further errors:
146 point = expect_func(row);
147 }
148#endif
149 value_type expected = expect_func(row);
150 value_type err = relative_error(point, expected);
151#ifdef BOOST_INSTRUMENT
152 if(err != 0)
153 {
154 std::cout << row[0] << " " << err;
155 if(std::numeric_limits<value_type>::is_specialized)
156 {
157 std::cout << " (" << err / std::numeric_limits<value_type>::epsilon() << "eps)";
158 }
159 std::cout << std::endl;
160 }
161#endif
162 if(!(boost::math::isfinite)(point) && (boost::math::isfinite)(expected))
163 {
164 std::cerr << "CAUTION: Found non-finite result, when a finite value was expected at entry " << i << "\n";
165 std::cerr << "Found: " << point << " Expected " << expected << " Error: " << err << std::endl;
166 print_row(row, std::cerr);
167 BOOST_ERROR("Unexpected non-finite result");
168 }
169 if(err > 0.5)
170 {
171 std::cerr << "CAUTION: Gross error found at entry " << i << ".\n";
172 std::cerr << "Found: " << point << " Expected " << expected << " Error: " << err << std::endl;
173 print_row(row, std::cerr);
174 BOOST_ERROR("Gross error");
175 }
176 result.add(err);
177 if((result.max)() == err)
178 result.set_worst(i);
179 }
180 return result;
181}
182
183template <class Real, class A, class F1, class F2>
184test_result<Real> test_hetero(const A& a, F1 test_func, F2 expect_func)
185{
186 typedef typename A::value_type row_type;
187 typedef Real value_type;
188
189 test_result<value_type> result;
190
191 for(unsigned i = 0; i < a.size(); ++i)
192 {
193 const row_type& row = a[i];
194 value_type point;
195#ifndef BOOST_NO_EXCEPTIONS
196 try
197 {
198#endif
199 point = test_func(row);
200#ifndef BOOST_NO_EXCEPTIONS
201 }
202 catch(const std::underflow_error&)
203 {
204 point = 0;
205 }
206 catch(const std::overflow_error&)
207 {
208 point = std::numeric_limits<value_type>::has_infinity ?
209 std::numeric_limits<value_type>::infinity()
210 : tools::max_value<value_type>();
211 }
212 catch(const std::exception& e)
213 {
92f5a8d4 214 std::cerr << "Unexpected exception at entry: " << i << "\n";
7c673cae
FG
215 std::cerr << e.what() << std::endl;
216 print_row(row, std::cerr);
217 BOOST_ERROR("Unexpected exception.");
218 // so we don't get further errors:
219 point = expect_func(row);
220 }
221#endif
222 value_type expected = expect_func(row);
223 value_type err = relative_error(point, expected);
224#ifdef BOOST_INSTRUMENT
225 if(err != 0)
226 {
227 std::cout << row[0] << " " << err;
228 if(std::numeric_limits<value_type>::is_specialized)
229 {
230 std::cout << " (" << err / std::numeric_limits<value_type>::epsilon() << "eps)";
231 }
232 std::cout << std::endl;
233 }
234#endif
235 if(!(boost::math::isfinite)(point) && (boost::math::isfinite)(expected))
236 {
237 std::cerr << "CAUTION: Found non-finite result, when a finite value was expected at entry " << i << "\n";
238 std::cerr << "Found: " << point << " Expected " << expected << " Error: " << err << std::endl;
239 print_row(row, std::cerr);
240 BOOST_ERROR("Unexpected non-finite result");
241 }
242 if(err > 0.5)
243 {
244 std::cerr << "CAUTION: Gross error found at entry " << i << ".\n";
245 std::cerr << "Found: " << point << " Expected " << expected << " Error: " << err << std::endl;
246 print_row(row, std::cerr);
247 BOOST_ERROR("Gross error");
248 }
249 result.add(err);
250 if((result.max)() == err)
251 result.set_worst(i);
252 }
253 return result;
254}
255
256template <class Val, class Exception>
257void test_check_throw(Val v, Exception e)
258{
259 BOOST_CHECK(errno);
260 errno = 0;
261}
262
263template <class Val>
264void test_check_throw(Val val, std::domain_error const* e)
265{
266 BOOST_CHECK(errno == EDOM);
267 errno = 0;
268 if(std::numeric_limits<Val>::has_quiet_NaN)
269 {
270 BOOST_CHECK((boost::math::isnan)(val));
271 }
272}
273
274template <class Val>
275void test_check_throw(Val v, std::overflow_error const* e)
276{
277 BOOST_CHECK(errno == ERANGE);
278 errno = 0;
279 BOOST_CHECK((v >= boost::math::tools::max_value<Val>()) || (v <= -boost::math::tools::max_value<Val>()));
280}
281
282template <class Val>
283void test_check_throw(Val v, boost::math::rounding_error const* e)
284{
285 BOOST_CHECK(errno == ERANGE);
286 errno = 0;
287 if(std::numeric_limits<Val>::is_specialized && std::numeric_limits<Val>::is_integer)
288 {
289 BOOST_CHECK((v == (std::numeric_limits<Val>::max)()) || (v == (std::numeric_limits<Val>::min)()));
290 }
291 else
292 {
293 BOOST_CHECK((v == boost::math::tools::max_value<Val>()) || (v == -boost::math::tools::max_value<Val>()));
294 }
295}
296
297} // namespace tools
298} // namespace math
299} // namespace boost
300
301
302 //
303 // exception-free testing support, ideally we'd only define this in our tests,
304 // but to keep things simple we really need it somewhere that's always included:
305 //
306#ifdef BOOST_NO_EXCEPTIONS
307# define BOOST_MATH_CHECK_THROW(x, ExceptionType) boost::math::tools::test_check_throw(x, static_cast<ExceptionType const*>(0));
308#else
309# define BOOST_MATH_CHECK_THROW(x, y) BOOST_CHECK_THROW(x, y)
310#endif
311
312#endif
313
314