]>
Commit | Line | Data |
---|---|---|
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 | #include <pch.hpp> | |
7 | ||
8 | #include <boost/math/concepts/real_concept.hpp> | |
9 | #include <boost/math/special_functions/acosh.hpp> | |
10 | #include <boost/math/special_functions/asinh.hpp> | |
11 | #include <boost/math/special_functions/atanh.hpp> | |
12 | #define BOOST_TEST_MAIN | |
13 | #include <boost/test/unit_test.hpp> | |
14 | #include <boost/test/floating_point_comparison.hpp> | |
15 | #include <boost/math/tools/stats.hpp> | |
16 | #include <boost/math/tools/test.hpp> | |
17 | #include <boost/math/constants/constants.hpp> | |
18 | #include <boost/type_traits/is_floating_point.hpp> | |
19 | #include <boost/array.hpp> | |
20 | #include "functor.hpp" | |
21 | ||
22 | #include "handle_test_result.hpp" | |
23 | #include "table_type.hpp" | |
24 | ||
25 | #include <iostream> | |
26 | #include <iomanip> | |
27 | // | |
28 | // DESCRIPTION: | |
29 | // ~~~~~~~~~~~~ | |
30 | // | |
31 | // This file tests the inverse hyperbolic functions. There are two sets of tests: | |
32 | // 1) Sanity checks: comparison to test values created with the | |
33 | // online calculator at functions.wolfram.com | |
b32b8144 | 34 | // 2) Accuracy tests use values generated with NTL::RR at |
7c673cae FG |
35 | // 1000-bit precision and our generic versions of these functions. |
36 | // | |
37 | // Note that when this file is first run on a new platform many of | |
38 | // these tests will fail: the default accuracy is 1 epsilon which | |
b32b8144 | 39 | // is too tight for most platforms. In this situation you will |
7c673cae FG |
40 | // need to cast a human eye over the error rates reported and make |
41 | // a judgement as to whether they are acceptable. Either way please | |
42 | // report the results to the Boost mailing list. Acceptable rates of | |
43 | // error are marked up below as a series of regular expressions that | |
44 | // identify the compiler/stdlib/platform/data-type/test-data/test-function | |
45 | // along with the maximum expected peek and RMS mean errors for that | |
46 | // test. | |
47 | // | |
48 | ||
49 | void expected_results() | |
50 | { | |
51 | // | |
52 | // Define the max and mean errors expected for | |
53 | // various compilers and platforms. | |
54 | // | |
55 | const char* largest_type; | |
56 | #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS | |
57 | if(boost::math::policies::digits<double, boost::math::policies::policy<> >() == boost::math::policies::digits<long double, boost::math::policies::policy<> >()) | |
58 | { | |
59 | largest_type = "(long\\s+)?double|real_concept"; | |
60 | } | |
61 | else | |
62 | { | |
63 | largest_type = "long double|real_concept"; | |
64 | } | |
65 | #else | |
66 | largest_type = "(long\\s+)?double"; | |
67 | #endif | |
68 | ||
69 | add_expected_result( | |
70 | ".*", // compiler | |
71 | ".*", // stdlib | |
72 | ".*", // platform | |
73 | largest_type, // test type(s) | |
74 | "atanh.*", // test data group | |
75 | ".*", 6, 1); // test function | |
76 | add_expected_result( | |
77 | ".*", // compiler | |
78 | ".*", // stdlib | |
79 | ".*", // platform | |
80 | "real_concept", // test type(s) | |
81 | ".*", // test data group | |
82 | ".*", 4, 2); // test function | |
83 | add_expected_result( | |
84 | ".*", // compiler | |
85 | ".*", // stdlib | |
86 | ".*", // platform | |
87 | largest_type, // test type(s) | |
88 | ".*", // test data group | |
89 | ".*", 4, 1); // test function | |
90 | ||
b32b8144 | 91 | std::cout << "Tests run with " << BOOST_COMPILER << ", " |
7c673cae FG |
92 | << BOOST_STDLIB << ", " << BOOST_PLATFORM << std::endl; |
93 | } | |
94 | ||
95 | template <class Real, class T> | |
96 | void do_test_asinh(const T& data, const char* type_name, const char* test_name) | |
97 | { | |
98 | // | |
99 | // test asinh(T) against data: | |
100 | // | |
101 | using namespace std; | |
7c673cae FG |
102 | typedef Real value_type; |
103 | ||
104 | std::cout << test_name << " with type " << type_name << std::endl; | |
105 | ||
106 | typedef value_type (*pg)(value_type); | |
107 | #if defined(BOOST_MATH_NO_DEDUCED_FUNCTION_POINTERS) | |
108 | pg funcp = boost::math::asinh<value_type>; | |
109 | #else | |
110 | pg funcp = boost::math::asinh; | |
111 | #endif | |
112 | ||
113 | boost::math::tools::test_result<value_type> result; | |
114 | // | |
115 | // test asinh against data: | |
116 | // | |
117 | result = boost::math::tools::test_hetero<Real>( | |
118 | data, | |
119 | bind_func<Real>(funcp, 0), | |
120 | extract_result<Real>(1)); | |
121 | handle_test_result(result, data[result.worst()], result.worst(), type_name, "boost::math::asinh", test_name); | |
122 | std::cout << std::endl; | |
123 | } | |
124 | ||
125 | template <class Real, class T> | |
126 | void do_test_acosh(const T& data, const char* type_name, const char* test_name) | |
127 | { | |
128 | // | |
129 | // test acosh(T) against data: | |
130 | // | |
131 | using namespace std; | |
7c673cae FG |
132 | typedef Real value_type; |
133 | ||
134 | std::cout << test_name << " with type " << type_name << std::endl; | |
135 | ||
136 | typedef value_type (*pg)(value_type); | |
137 | #if defined(BOOST_MATH_NO_DEDUCED_FUNCTION_POINTERS) | |
138 | pg funcp = boost::math::acosh<value_type>; | |
139 | #else | |
140 | pg funcp = boost::math::acosh; | |
141 | #endif | |
142 | ||
143 | boost::math::tools::test_result<value_type> result; | |
144 | // | |
145 | // test acosh against data: | |
146 | // | |
147 | result = boost::math::tools::test_hetero<Real>( | |
148 | data, | |
149 | bind_func<Real>(funcp, 0), | |
150 | extract_result<Real>(1)); | |
151 | handle_test_result(result, data[result.worst()], result.worst(), type_name, "boost::math::acosh", test_name); | |
152 | std::cout << std::endl; | |
153 | } | |
154 | ||
155 | template <class Real, class T> | |
156 | void do_test_atanh(const T& data, const char* type_name, const char* test_name) | |
157 | { | |
158 | // | |
159 | // test atanh(T) against data: | |
160 | // | |
161 | using namespace std; | |
7c673cae FG |
162 | typedef Real value_type; |
163 | ||
164 | std::cout << test_name << " with type " << type_name << std::endl; | |
165 | ||
166 | typedef value_type (*pg)(value_type); | |
167 | #if defined(BOOST_MATH_NO_DEDUCED_FUNCTION_POINTERS) | |
168 | pg funcp = boost::math::atanh<value_type>; | |
169 | #else | |
170 | pg funcp = boost::math::atanh; | |
171 | #endif | |
172 | ||
173 | boost::math::tools::test_result<value_type> result; | |
174 | // | |
175 | // test atanh against data: | |
176 | // | |
177 | result = boost::math::tools::test_hetero<Real>( | |
178 | data, | |
179 | bind_func<Real>(funcp, 0), | |
180 | extract_result<Real>(1)); | |
181 | handle_test_result(result, data[result.worst()], result.worst(), type_name, "boost::math::atanh", test_name); | |
182 | std::cout << std::endl; | |
183 | } | |
184 | ||
185 | template <class T> | |
186 | void test_inv_hyperbolics(T, const char* name) | |
187 | { | |
188 | // function values calculated on http://functions.wolfram.com/ | |
189 | #define SC_(x) static_cast<typename table_type<T>::type>(BOOST_JOIN(x, L)) | |
190 | static const boost::array<boost::array<typename table_type<T>::type, 2>, 16> data1 = {{ | |
191 | {{ SC_(1.0), SC_(0.0) }}, | |
192 | {{ SC_(18014398509481985.0)/SC_(18014398509481984.0), (SC_(18014398509481985.0)/SC_(18014398509481984.0) == 1 ? 0 : SC_(1.05367121277235078980001569764860129317209081216314559121044e-8)) }}, | |
193 | {{ SC_(140737488355329.0)/SC_(140737488355328.0), (SC_(140737488355329.0)/SC_(140737488355328.0) == 1 ? 0 : SC_(1.19209289550781179413921062141751258430803882725295121500042e-7)) }}, | |
194 | {{ SC_(1073741825.0)/SC_(1073741824.0), (SC_(1073741825.0)/SC_(1073741824.0) == 1 ? 0 : SC_(0.0000431583728718059579720327225039166883356735150941350459126580)) }}, | |
195 | {{ SC_(32769.0)/32768, (SC_(32769.0)/32768 == 1 ? 0 : SC_(0.00781248013192149783598227588546120945538554063153555218442060)) }}, | |
196 | {{ SC_(1025.0)/1024, SC_(0.0441905780831100944299637635287994671116916497867872322058681) }}, | |
197 | {{ SC_(513.0)/512, SC_(0.0624898319417098609694799246056217361555882834152944713872228) }}, | |
198 | {{ SC_(129.0)/128, SC_(0.124918762511080617606418193883982155828039646714882611321039) }}, | |
199 | {{ SC_(33.0)/32, SC_(0.249353493842885487851439075410018843027071727873456825299808) }}, | |
200 | {{ SC_(5.0)/4, SC_(0.693147180559945309417232121458176568075500134360255254120680) }}, | |
201 | {{ SC_(3.0)/2, SC_(0.962423650119206894995517826848736846270368668771321039322036) }}, | |
202 | {{ SC_(1.75), SC_(1.15881036042994681173087299087873019318368454205435905403767) }}, | |
203 | {{ SC_(2.0), SC_(1.31695789692481670862504634730796844402698197146751647976847) }}, | |
204 | {{ SC_(20.0), SC_(3.68825386736129666761816757203235188783315569765587425882926) }}, | |
205 | {{ SC_(200.0), SC_(5.99145829704938742305501213819154333467246121857058747847273) }}, | |
206 | {{ SC_(2000.0), SC_(8.29404957760202181151262480475259799729149903827743516943515) }}, | |
207 | }}; | |
208 | #undef SC_ | |
209 | ||
210 | // | |
211 | // The actual test data is rather verbose, so it's in a separate file | |
212 | // | |
213 | #include "asinh_data.ipp" | |
214 | do_test_asinh<T>(asinh_data, name, "asinh"); | |
215 | #include "acosh_data.ipp" | |
216 | do_test_acosh<T>(data1, name, "acosh: Mathworld Data"); | |
217 | do_test_acosh<T>(acosh_data, name, "acosh"); | |
218 | #include "atanh_data.ipp" | |
219 | do_test_atanh<T>(atanh_data, name, "atanh"); | |
220 | } | |
221 | ||
222 | extern "C" double zetac(double); | |
223 | ||
224 | template <class T> | |
225 | void test_spots(T, const char* t) | |
226 | { | |
227 | std::cout << "Testing basic sanity checks for type " << t << std::endl; | |
228 | // | |
b32b8144 | 229 | // Basic sanity checks, tolerance is either 5 or 10 epsilon |
7c673cae FG |
230 | // expressed as a percentage: |
231 | // | |
232 | T tolerance = boost::math::tools::epsilon<T>() * 100 * | |
233 | (boost::is_floating_point<T>::value ? 5 : 10); | |
234 | BOOST_CHECK_CLOSE(::boost::math::acosh(static_cast<T>(262145)/262144L), static_cast<T>(0.00276213498595136093375633956331651432309750291610866833462649L), tolerance); | |
235 | BOOST_CHECK_CLOSE(::boost::math::acosh(static_cast<T>(2)), static_cast<T>(1.31695789692481670862504634730796844402698197146751647976847L), tolerance); | |
236 | BOOST_CHECK_CLOSE(::boost::math::acosh(static_cast<T>(40)), static_cast<T>(4.38187034804006698696313269586603717076961771721038534547948L), tolerance); | |
237 | BOOST_CHECK_CLOSE(::boost::math::acosh(static_cast<T>(262145L)), static_cast<T>(13.1698002453253126137651962522659827810753786944786303017757L), tolerance); | |
238 | ||
239 | BOOST_CHECK_CLOSE(::boost::math::asinh(static_cast<T>(0)), static_cast<T>(0), tolerance); | |
240 | BOOST_CHECK_CLOSE(::boost::math::asinh(static_cast<T>(1)/262145L), static_cast<T>(3.81468271375603081996185039385472561751449912305225962381803e-6L), tolerance); | |
241 | BOOST_CHECK_CLOSE(::boost::math::asinh(static_cast<T>(0.25)), static_cast<T>(0.247466461547263452944781549788359289253766903098567696469117L), tolerance); | |
242 | BOOST_CHECK_CLOSE(::boost::math::asinh(static_cast<T>(1)), static_cast<T>(0.881373587019543025232609324979792309028160328261635410753296L), tolerance); | |
243 | BOOST_CHECK_CLOSE(::boost::math::asinh(static_cast<T>(10)), static_cast<T>(2.99822295029796973884659553759645347660705805487730365573446L), tolerance); | |
244 | BOOST_CHECK_CLOSE(::boost::math::asinh(static_cast<T>(262145L)), static_cast<T>(13.1698002453325885158685460826511173257938039316922010439486L), tolerance); | |
245 | ||
246 | BOOST_CHECK_CLOSE(::boost::math::atanh(static_cast<T>(0)), static_cast<T>(0), tolerance); | |
247 | BOOST_CHECK_CLOSE(::boost::math::atanh(static_cast<T>(1)/262145L), static_cast<T>(3.81468271378378607794264842456613940280945630999769224301574e-6L), tolerance); | |
248 | BOOST_CHECK_CLOSE(::boost::math::atanh(static_cast<T>(-1)/262145L), static_cast<T>(-3.81468271378378607794264842456613940280945630999769224301574e-6L), tolerance); | |
249 | BOOST_CHECK_CLOSE(::boost::math::atanh(static_cast<T>(0.5)), static_cast<T>(0.549306144334054845697622618461262852323745278911374725867347L), tolerance); | |
250 | BOOST_CHECK_CLOSE(::boost::math::atanh(static_cast<T>(-0.5)), static_cast<T>(-0.549306144334054845697622618461262852323745278911374725867347L), tolerance); | |
251 | } | |
252 | ||
253 | BOOST_AUTO_TEST_CASE( test_main ) | |
254 | { | |
255 | expected_results(); | |
256 | BOOST_MATH_CONTROL_FP; | |
257 | ||
258 | test_spots(0.0f, "float"); | |
259 | test_spots(0.0, "double"); | |
260 | #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS | |
261 | test_spots(0.0L, "long double"); | |
262 | #ifndef BOOST_MATH_NO_REAL_CONCEPT_TESTS | |
263 | test_spots(boost::math::concepts::real_concept(0.1), "real_concept"); | |
264 | #endif | |
265 | #else | |
266 | std::cout << "<note>The long double tests have been disabled on this platform " | |
267 | "either because the long double overloads of the usual math functions are " | |
268 | "not available at all, or because they are too inaccurate for these tests " | |
269 | "to pass.</note>" << std::endl; | |
270 | #endif | |
271 | ||
272 | test_inv_hyperbolics(0.1F, "float"); | |
273 | test_inv_hyperbolics(0.1, "double"); | |
274 | #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS | |
275 | test_inv_hyperbolics(0.1L, "long double"); | |
276 | #ifndef BOOST_MATH_NO_REAL_CONCEPT_TESTS | |
277 | test_inv_hyperbolics(boost::math::concepts::real_concept(0.1), "real_concept"); | |
278 | #endif | |
279 | #else | |
280 | std::cout << "<note>The long double tests have been disabled on this platform " | |
281 | "either because the long double overloads of the usual math functions are " | |
282 | "not available at all, or because they are too inaccurate for these tests " | |
283 | "to pass.</note>" << std::endl; | |
284 | #endif | |
7c673cae | 285 | |
b32b8144 | 286 | } |