]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/math/example/policy_eg_9.cpp
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / boost / libs / math / example / policy_eg_9.cpp
CommitLineData
7c673cae
FG
1// Copyright John Maddock 2007.
2// Copyright Paul A. Bristow 2010
3// Use, modification and distribution are subject to the
4// Boost Software License, Version 1.0. (See accompanying file
5// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6
7// Note that this file contains quickbook mark-up as well as code
8// and comments, don't change any of the special comment mark-ups!
9
10#include <iostream>
11#include <boost/format.hpp>
12using std::cout; using std::endl; using std::cerr;
13
14//[policy_eg_9
15
16/*`
17The previous example was all well and good, but the custom error handlers
18didn't really do much of any use. In this example we'll implement all
19the custom handlers and show how the information provided to them can be
20used to generate nice formatted error messages.
21
22Each error handler has the general form:
23
24 template <class T>
25 T user_``['error_type]``(
26 const char* function,
27 const char* message,
28 const T& val);
29
30and accepts three arguments:
31
32[variablelist
33[[const char* function]
34 [The name of the function that raised the error, this string
35 contains one or more %1% format specifiers that should be
36 replaced by the name of real type T, like float or double.]]
37[[const char* message]
38 [A message associated with the error, normally this
39 contains a %1% format specifier that should be replaced with
40 the value of ['value]: however note that overflow and underflow messages
41 do not contain this %1% specifier (since the value of ['value] is
42 immaterial in these cases).]]
43[[const T& value]
44 [The value that caused the error: either an argument to the function
45 if this is a domain or pole error, the tentative result
46 if this is a denorm or evaluation error, or zero or infinity for
47 underflow or overflow errors.]]
48]
49
50As before we'll include the headers we need first:
51
52*/
53
54#include <boost/math/special_functions.hpp>
55
56/*`
57Next we'll implement our own error handlers for each type of error,
58starting with domain errors:
59*/
60
61namespace boost{ namespace math{
62namespace policies
63{
64
65template <class T>
66T user_domain_error(const char* function, const char* message, const T& val)
67{
68 /*`
69 We'll begin with a bit of defensive programming in case function or message are empty:
70 */
71 if(function == 0)
72 function = "Unknown function with arguments of type %1%";
73 if(message == 0)
74 message = "Cause unknown with bad argument %1%";
75 /*`
76 Next we'll format the name of the function with the name of type T, perhaps double:
77 */
78 std::string msg("Error in function ");
79 msg += (boost::format(function) % typeid(T).name()).str();
80 /*`
81 Then likewise format the error message with the value of parameter /val/,
82 making sure we output all the potentially significant digits of /val/:
83 */
84 msg += ": \n";
85 int prec = 2 + (std::numeric_limits<T>::digits * 30103UL) / 100000UL;
86 // int prec = std::numeric_limits<T>::max_digits10; // For C++0X Standard Library
87 msg += (boost::format(message) % boost::io::group(std::setprecision(prec), val)).str();
88 /*`
89 Now we just have to do something with the message, we could throw an
90 exception, but for the purposes of this example we'll just dump the message
91 to std::cerr:
92 */
93 std::cerr << msg << std::endl;
94 /*`
95 Finally the only sensible value we can return from a domain error is a NaN:
96 */
97 return std::numeric_limits<T>::quiet_NaN();
98}
99
100/*`
101Pole errors are essentially a special case of domain errors,
102so in this example we'll just return the result of a domain error:
103*/
104
105template <class T>
106T user_pole_error(const char* function, const char* message, const T& val)
107{
108 return user_domain_error(function, message, val);
109}
110
111/*`
112Overflow errors are very similar to domain errors, except that there's
113no %1% format specifier in the /message/ parameter:
114*/
115template <class T>
116T user_overflow_error(const char* function, const char* message, const T& val)
117{
118 if(function == 0)
119 function = "Unknown function with arguments of type %1%";
120 if(message == 0)
121 message = "Result of function is too large to represent";
122
123 std::string msg("Error in function ");
124 msg += (boost::format(function) % typeid(T).name()).str();
125
126 msg += ": \n";
127 msg += message;
128
129 std::cerr << msg << std::endl;
130
131 // Value passed to the function is an infinity, just return it:
132 return val;
133}
134
135/*`
136Underflow errors are much the same as overflow:
137*/
138
139template <class T>
140T user_underflow_error(const char* function, const char* message, const T& val)
141{
142 if(function == 0)
143 function = "Unknown function with arguments of type %1%";
144 if(message == 0)
145 message = "Result of function is too small to represent";
146
147 std::string msg("Error in function ");
148 msg += (boost::format(function) % typeid(T).name()).str();
149
150 msg += ": \n";
151 msg += message;
152
153 std::cerr << msg << std::endl;
154
155 // Value passed to the function is zero, just return it:
156 return val;
157}
158
159/*`
160Denormalised results are much the same as underflow:
161*/
162
163template <class T>
164T user_denorm_error(const char* function, const char* message, const T& val)
165{
166 if(function == 0)
167 function = "Unknown function with arguments of type %1%";
168 if(message == 0)
169 message = "Result of function is denormalised";
170
171 std::string msg("Error in function ");
172 msg += (boost::format(function) % typeid(T).name()).str();
173
174 msg += ": \n";
175 msg += message;
176
177 std::cerr << msg << std::endl;
178
179 // Value passed to the function is denormalised, just return it:
180 return val;
181}
182
183/*`
184Which leaves us with evaluation errors: these occur when an internal
185error occurs that prevents the function being fully evaluated.
186The parameter /val/ contains the closest approximation to the result
187found so far:
188*/
189
190template <class T>
191T user_evaluation_error(const char* function, const char* message, const T& val)
192{
193 if(function == 0)
194 function = "Unknown function with arguments of type %1%";
195 if(message == 0)
196 message = "An internal evaluation error occurred with "
197 "the best value calculated so far of %1%";
198
199 std::string msg("Error in function ");
200 msg += (boost::format(function) % typeid(T).name()).str();
201
202 msg += ": \n";
203 int prec = 2 + (std::numeric_limits<T>::digits * 30103UL) / 100000UL;
204 // int prec = std::numeric_limits<T>::max_digits10; // For C++0X Standard Library
205 msg += (boost::format(message) % boost::io::group(std::setprecision(prec), val)).str();
206
207 std::cerr << msg << std::endl;
208
209 // What do we return here? This is generally a fatal error, that should never occur,
210 // so we just return a NaN for the purposes of the example:
211 return std::numeric_limits<T>::quiet_NaN();
212}
213
214} // policies
215}} // boost::math
216
217
218/*`
219Now we'll need to define a suitable policy that will call these handlers,
220and define some forwarding functions that make use of the policy:
221*/
222
223namespace mymath
224{ // unnamed.
225
226using namespace boost::math::policies;
227
228typedef policy<
229 domain_error<user_error>,
230 pole_error<user_error>,
231 overflow_error<user_error>,
232 underflow_error<user_error>,
233 denorm_error<user_error>,
234 evaluation_error<user_error>
235> user_error_policy;
236
237BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(user_error_policy)
238
239} // unnamed namespace
240
241/*`
242We now have a set of forwarding functions, defined in namespace mymath,
243that all look something like this:
244
245``
246template <class RealType>
247inline typename boost::math::tools::promote_args<RT>::type
248 tgamma(RT z)
249{
250 return boost::math::tgamma(z, user_error_policy());
251}
252``
253
254So that when we call `mymath::tgamma(z)` we really end up calling
255`boost::math::tgamma(z, user_error_policy())`, and any
256errors will get directed to our own error handlers:
257*/
258
259int main()
260{
261 // Raise a domain error:
262 cout << "Result of erf_inv(-10) is: "
263 << mymath::erf_inv(-10) << std::endl << endl;
264 // Raise a pole error:
265 cout << "Result of tgamma(-10) is: "
266 << mymath::tgamma(-10) << std::endl << endl;
267 // Raise an overflow error:
268 cout << "Result of tgamma(3000) is: "
269 << mymath::tgamma(3000) << std::endl << endl;
270 // Raise an underflow error:
271 cout << "Result of tgamma(-190.5) is: "
272 << mymath::tgamma(-190.5) << std::endl << endl;
f67539c2 273 // Unfortunately we can't predictably raise a denormalised
7c673cae
FG
274 // result, nor can we raise an evaluation error in this example
275 // since these should never really occur!
276} // int main()
277
278/*`
279
280Which outputs:
281
282[pre
283Error in function boost::math::erf_inv<double>(double, double):
284Argument outside range \[-1, 1\] in inverse erf function (got p=-10).
285Result of erf_inv(-10) is: 1.#QNAN
286
287Error in function boost::math::tgamma<long double>(long double):
288Evaluation of tgamma at a negative integer -10.
289Result of tgamma(-10) is: 1.#QNAN
290
291Error in function boost::math::tgamma<long double>(long double):
292Result of tgamma is too large to represent.
293Error in function boost::math::tgamma<double>(double):
294Result of function is too large to represent
295Result of tgamma(3000) is: 1.#INF
296
297Error in function boost::math::tgamma<long double>(long double):
298Result of tgamma is too large to represent.
299Error in function boost::math::tgamma<long double>(long double):
300Result of tgamma is too small to represent.
301Result of tgamma(-190.5) is: 0
302]
303
304Notice how some of the calls result in an error handler being called more
305than once, or for more than one handler to be called: this is an artefact
306of the fact that many functions are implemented in terms of one or more
307sub-routines each of which may have it's own error handling. For example
308`tgamma(-190.5)` is implemented in terms of `tgamma(190.5)` - which overflows -
309the reflection formula for `tgamma` then notices that it is dividing by
310infinity and so underflows.
311*/
312
313//] //[/policy_eg_9]