1 // Copyright John Maddock 2007.
2 // Copyright Paul A. Bristow 2007.
3
4 // Use, modification and distribution are subject to the
5 // Boost Software License, Version 1.0. (See accompanying file
6 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7
8 #ifndef BOOST_MATH_POLICY_ERROR_HANDLING_HPP
9 #define BOOST_MATH_POLICY_ERROR_HANDLING_HPP
10
11 #include <stdexcept>
12 #include <iomanip>
13 #include <string>
14 #include <cstring>
15 #include <typeinfo>
16 #include <cerrno>
17 #include <boost/config/no_tr1/complex.hpp>
18 #include <boost/config/no_tr1/cmath.hpp>
19 #include <stdexcept>
20 #include <boost/math/tools/config.hpp>
21 #include <boost/math/policies/policy.hpp>
22 #include <boost/math/tools/precision.hpp>
23 #include <boost/throw_exception.hpp>
24 #include <boost/cstdint.hpp>
25 #ifdef BOOST_MSVC
26 # pragma warning(push) // Quiet warnings in boost/format.hpp
27 # pragma warning(disable: 4996) // _SCL_SECURE_NO_DEPRECATE
28 # pragma warning(disable: 4512) // assignment operator could not be generated.
29 # pragma warning(disable: 4127) // conditional expression is constant
30 // And warnings in error handling:
31 # pragma warning(disable: 4702) // unreachable code.
32 // Note that this only occurs when the compiler can deduce code is unreachable,
33 // for example when policy macros are used to ignore errors rather than throw.
34 #endif
35 #include <sstream>
36
37 namespace boost{ namespace math{
38
39 class evaluation_error : public std::runtime_error
40 {
41 public:
evaluation_error(const std::string & s)42 evaluation_error(const std::string& s) : std::runtime_error(s){}
43 };
44
45 class rounding_error : public std::runtime_error
46 {
47 public:
rounding_error(const std::string & s)48 rounding_error(const std::string& s) : std::runtime_error(s){}
49 };
50
51 namespace policies{
52 //
53 // Forward declarations of user error handlers,
54 // it's up to the user to provide the definition of these:
55 //
56 template <class T>
57 T user_domain_error(const char* function, const char* message, const T& val);
58 template <class T>
59 T user_pole_error(const char* function, const char* message, const T& val);
60 template <class T>
61 T user_overflow_error(const char* function, const char* message, const T& val);
62 template <class T>
63 T user_underflow_error(const char* function, const char* message, const T& val);
64 template <class T>
65 T user_denorm_error(const char* function, const char* message, const T& val);
66 template <class T>
67 T user_evaluation_error(const char* function, const char* message, const T& val);
68 template <class T, class TargetType>
69 T user_rounding_error(const char* function, const char* message, const T& val, const TargetType& t);
70 template <class T>
71 T user_indeterminate_result_error(const char* function, const char* message, const T& val);
72
73 namespace detail
74 {
75
76 template <class T>
prec_format(const T & val)77 std::string prec_format(const T& val)
78 {
79 typedef typename boost::math::policies::precision<T, boost::math::policies::policy<> >::type prec_type;
80 std::stringstream ss;
81 if(prec_type::value)
82 {
83 int prec = 2 + (prec_type::value * 30103UL) / 100000UL;
84 ss << std::setprecision(prec);
85 }
86 ss << val;
87 return ss.str();
88 }
89
replace_all_in_string(std::string & result,const char * what,const char * with)90 inline void replace_all_in_string(std::string& result, const char* what, const char* with)
91 {
92 std::string::size_type pos = 0;
93 std::string::size_type slen = std::strlen(what);
94 std::string::size_type rlen = std::strlen(with);
95 while((pos = result.find(what, pos)) != std::string::npos)
96 {
97 result.replace(pos, slen, with);
98 pos += rlen;
99 }
100 }
101
102 template <class T>
name_of()103 inline const char* name_of()
104 {
105 #ifndef BOOST_NO_RTTI
106 return typeid(T).name();
107 #else
108 return "unknown";
109 #endif
110 }
name_of()111 template <> inline const char* name_of<float>(){ return "float"; }
name_of()112 template <> inline const char* name_of<double>(){ return "double"; }
name_of()113 template <> inline const char* name_of<long double>(){ return "long double"; }
114
115 #ifdef BOOST_MATH_USE_FLOAT128
116 template <>
name_of()117 inline const char* name_of<BOOST_MATH_FLOAT128_TYPE>()
118 {
119 return "__float128";
120 }
121 #endif
122
123 template <class E, class T>
raise_error(const char * pfunction,const char * message)124 void raise_error(const char* pfunction, const char* message)
125 {
126 if(pfunction == 0)
127 pfunction = "Unknown function operating on type %1%";
128 if(message == 0)
129 message = "Cause unknown";
130
131 std::string function(pfunction);
132 std::string msg("Error in function ");
133 #ifndef BOOST_NO_RTTI
134 replace_all_in_string(function, "%1%", boost::math::policies::detail::name_of<T>());
135 #else
136 replace_all_in_string(function, "%1%", "Unknown");
137 #endif
138 msg += function;
139 msg += ": ";
140 msg += message;
141
142 E e(msg);
143 boost::throw_exception(e);
144 }
145
146 template <class E, class T>
raise_error(const char * pfunction,const char * pmessage,const T & val)147 void raise_error(const char* pfunction, const char* pmessage, const T& val)
148 {
149 if(pfunction == 0)
150 pfunction = "Unknown function operating on type %1%";
151 if(pmessage == 0)
152 pmessage = "Cause unknown: error caused by bad argument with value %1%";
153
154 std::string function(pfunction);
155 std::string message(pmessage);
156 std::string msg("Error in function ");
157 #ifndef BOOST_NO_RTTI
158 replace_all_in_string(function, "%1%", boost::math::policies::detail::name_of<T>());
159 #else
160 replace_all_in_string(function, "%1%", "Unknown");
161 #endif
162 msg += function;
163 msg += ": ";
164
165 std::string sval = prec_format(val);
166 replace_all_in_string(message, "%1%", sval.c_str());
167 msg += message;
168
169 E e(msg);
170 boost::throw_exception(e);
171 }
172
173 template <class T>
raise_domain_error(const char * function,const char * message,const T & val,const::boost::math::policies::domain_error<::boost::math::policies::throw_on_error> &)174 inline T raise_domain_error(
175 const char* function,
176 const char* message,
177 const T& val,
178 const ::boost::math::policies::domain_error< ::boost::math::policies::throw_on_error>&)
179 {
180 raise_error<std::domain_error, T>(function, message, val);
181 // we never get here:
182 return std::numeric_limits<T>::quiet_NaN();
183 }
184
185 template <class T>
raise_domain_error(const char *,const char *,const T &,const::boost::math::policies::domain_error<::boost::math::policies::ignore_error> &)186 inline BOOST_MATH_CONSTEXPR T raise_domain_error(
187 const char* ,
188 const char* ,
189 const T& ,
190 const ::boost::math::policies::domain_error< ::boost::math::policies::ignore_error>&) BOOST_MATH_NOEXCEPT(T)
191 {
192 // This may or may not do the right thing, but the user asked for the error
193 // to be ignored so here we go anyway:
194 return std::numeric_limits<T>::quiet_NaN();
195 }
196
197 template <class T>
raise_domain_error(const char *,const char *,const T &,const::boost::math::policies::domain_error<::boost::math::policies::errno_on_error> &)198 inline T raise_domain_error(
199 const char* ,
200 const char* ,
201 const T& ,
202 const ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>&) BOOST_MATH_NOEXCEPT(T)
203 {
204 errno = EDOM;
205 // This may or may not do the right thing, but the user asked for the error
206 // to be silent so here we go anyway:
207 return std::numeric_limits<T>::quiet_NaN();
208 }
209
210 template <class T>
raise_domain_error(const char * function,const char * message,const T & val,const::boost::math::policies::domain_error<::boost::math::policies::user_error> &)211 inline T raise_domain_error(
212 const char* function,
213 const char* message,
214 const T& val,
215 const ::boost::math::policies::domain_error< ::boost::math::policies::user_error>&)
216 {
217 return user_domain_error(function, message, val);
218 }
219
220 template <class T>
raise_pole_error(const char * function,const char * message,const T & val,const::boost::math::policies::pole_error<::boost::math::policies::throw_on_error> &)221 inline T raise_pole_error(
222 const char* function,
223 const char* message,
224 const T& val,
225 const ::boost::math::policies::pole_error< ::boost::math::policies::throw_on_error>&)
226 {
227 return boost::math::policies::detail::raise_domain_error(function, message, val, ::boost::math::policies::domain_error< ::boost::math::policies::throw_on_error>());
228 }
229
230 template <class T>
raise_pole_error(const char * function,const char * message,const T & val,const::boost::math::policies::pole_error<::boost::math::policies::ignore_error> &)231 inline BOOST_MATH_CONSTEXPR T raise_pole_error(
232 const char* function,
233 const char* message,
234 const T& val,
235 const ::boost::math::policies::pole_error< ::boost::math::policies::ignore_error>&) BOOST_MATH_NOEXCEPT(T)
236 {
237 return ::boost::math::policies::detail::raise_domain_error(function, message, val, ::boost::math::policies::domain_error< ::boost::math::policies::ignore_error>());
238 }
239
240 template <class T>
raise_pole_error(const char * function,const char * message,const T & val,const::boost::math::policies::pole_error<::boost::math::policies::errno_on_error> &)241 inline BOOST_MATH_CONSTEXPR T raise_pole_error(
242 const char* function,
243 const char* message,
244 const T& val,
245 const ::boost::math::policies::pole_error< ::boost::math::policies::errno_on_error>&) BOOST_MATH_NOEXCEPT(T)
246 {
247 return ::boost::math::policies::detail::raise_domain_error(function, message, val, ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>());
248 }
249
250 template <class T>
raise_pole_error(const char * function,const char * message,const T & val,const::boost::math::policies::pole_error<::boost::math::policies::user_error> &)251 inline T raise_pole_error(
252 const char* function,
253 const char* message,
254 const T& val,
255 const ::boost::math::policies::pole_error< ::boost::math::policies::user_error>&)
256 {
257 return user_pole_error(function, message, val);
258 }
259
260
261 template <class T>
raise_overflow_error(const char * function,const char * message,const::boost::math::policies::overflow_error<::boost::math::policies::throw_on_error> &)262 inline T raise_overflow_error(
263 const char* function,
264 const char* message,
265 const ::boost::math::policies::overflow_error< ::boost::math::policies::throw_on_error>&)
266 {
267 raise_error<std::overflow_error, T>(function, message ? message : "numeric overflow");
268 // We should never get here:
269 return std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : boost::math::tools::max_value<T>();
270 }
271
272 template <class T>
raise_overflow_error(const char * function,const char * message,const T & val,const::boost::math::policies::overflow_error<::boost::math::policies::throw_on_error> &)273 inline T raise_overflow_error(
274 const char* function,
275 const char* message,
276 const T& val,
277 const ::boost::math::policies::overflow_error< ::boost::math::policies::throw_on_error>&)
278 {
279 raise_error<std::overflow_error, T>(function, message ? message : "numeric overflow", val);
280 // We should never get here:
281 return std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : boost::math::tools::max_value<T>();
282 }
283
284 template <class T>
raise_overflow_error(const char *,const char *,const::boost::math::policies::overflow_error<::boost::math::policies::ignore_error> &)285 inline BOOST_MATH_CONSTEXPR T raise_overflow_error(
286 const char* ,
287 const char* ,
288 const ::boost::math::policies::overflow_error< ::boost::math::policies::ignore_error>&) BOOST_MATH_NOEXCEPT(T)
289 {
290 // This may or may not do the right thing, but the user asked for the error
291 // to be ignored so here we go anyway:
292 return std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : boost::math::tools::max_value<T>();
293 }
294
295 template <class T>
raise_overflow_error(const char *,const char *,const T &,const::boost::math::policies::overflow_error<::boost::math::policies::ignore_error> &)296 inline BOOST_MATH_CONSTEXPR T raise_overflow_error(
297 const char* ,
298 const char* ,
299 const T&,
300 const ::boost::math::policies::overflow_error< ::boost::math::policies::ignore_error>&) BOOST_MATH_NOEXCEPT(T)
301 {
302 // This may or may not do the right thing, but the user asked for the error
303 // to be ignored so here we go anyway:
304 return std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : boost::math::tools::max_value<T>();
305 }
306
307 template <class T>
raise_overflow_error(const char *,const char *,const::boost::math::policies::overflow_error<::boost::math::policies::errno_on_error> &)308 inline T raise_overflow_error(
309 const char* ,
310 const char* ,
311 const ::boost::math::policies::overflow_error< ::boost::math::policies::errno_on_error>&) BOOST_MATH_NOEXCEPT(T)
312 {
313 errno = ERANGE;
314 // This may or may not do the right thing, but the user asked for the error
315 // to be silent so here we go anyway:
316 return std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : boost::math::tools::max_value<T>();
317 }
318
319 template <class T>
raise_overflow_error(const char *,const char *,const T &,const::boost::math::policies::overflow_error<::boost::math::policies::errno_on_error> &)320 inline T raise_overflow_error(
321 const char* ,
322 const char* ,
323 const T&,
324 const ::boost::math::policies::overflow_error< ::boost::math::policies::errno_on_error>&) BOOST_MATH_NOEXCEPT(T)
325 {
326 errno = ERANGE;
327 // This may or may not do the right thing, but the user asked for the error
328 // to be silent so here we go anyway:
329 return std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : boost::math::tools::max_value<T>();
330 }
331
332 template <class T>
raise_overflow_error(const char * function,const char * message,const::boost::math::policies::overflow_error<::boost::math::policies::user_error> &)333 inline T raise_overflow_error(
334 const char* function,
335 const char* message,
336 const ::boost::math::policies::overflow_error< ::boost::math::policies::user_error>&)
337 {
338 return user_overflow_error(function, message, std::numeric_limits<T>::infinity());
339 }
340
341 template <class T>
raise_overflow_error(const char * function,const char * message,const T & val,const::boost::math::policies::overflow_error<::boost::math::policies::user_error> &)342 inline T raise_overflow_error(
343 const char* function,
344 const char* message,
345 const T& val,
346 const ::boost::math::policies::overflow_error< ::boost::math::policies::user_error>&)
347 {
348 std::string m(message ? message : "");
349 std::string sval = prec_format(val);
350 replace_all_in_string(m, "%1%", sval.c_str());
351
352 return user_overflow_error(function, m.c_str(), std::numeric_limits<T>::infinity());
353 }
354
355 template <class T>
raise_underflow_error(const char * function,const char * message,const::boost::math::policies::underflow_error<::boost::math::policies::throw_on_error> &)356 inline T raise_underflow_error(
357 const char* function,
358 const char* message,
359 const ::boost::math::policies::underflow_error< ::boost::math::policies::throw_on_error>&)
360 {
361 raise_error<std::underflow_error, T>(function, message ? message : "numeric underflow");
362 // We should never get here:
363 return 0;
364 }
365
366 template <class T>
raise_underflow_error(const char *,const char *,const::boost::math::policies::underflow_error<::boost::math::policies::ignore_error> &)367 inline BOOST_MATH_CONSTEXPR T raise_underflow_error(
368 const char* ,
369 const char* ,
370 const ::boost::math::policies::underflow_error< ::boost::math::policies::ignore_error>&) BOOST_MATH_NOEXCEPT(T)
371 {
372 // This may or may not do the right thing, but the user asked for the error
373 // to be ignored so here we go anyway:
374 return T(0);
375 }
376
377 template <class T>
raise_underflow_error(const char *,const char *,const::boost::math::policies::underflow_error<::boost::math::policies::errno_on_error> &)378 inline T raise_underflow_error(
379 const char* /* function */,
380 const char* /* message */,
381 const ::boost::math::policies::underflow_error< ::boost::math::policies::errno_on_error>&) BOOST_MATH_NOEXCEPT(T)
382 {
383 errno = ERANGE;
384 // This may or may not do the right thing, but the user asked for the error
385 // to be silent so here we go anyway:
386 return T(0);
387 }
388
389 template <class T>
raise_underflow_error(const char * function,const char * message,const::boost::math::policies::underflow_error<::boost::math::policies::user_error> &)390 inline T raise_underflow_error(
391 const char* function,
392 const char* message,
393 const ::boost::math::policies::underflow_error< ::boost::math::policies::user_error>&)
394 {
395 return user_underflow_error(function, message, T(0));
396 }
397
398 template <class T>
raise_denorm_error(const char * function,const char * message,const T &,const::boost::math::policies::denorm_error<::boost::math::policies::throw_on_error> &)399 inline T raise_denorm_error(
400 const char* function,
401 const char* message,
402 const T& /* val */,
403 const ::boost::math::policies::denorm_error< ::boost::math::policies::throw_on_error>&)
404 {
405 raise_error<std::underflow_error, T>(function, message ? message : "denormalised result");
406 // we never get here:
407 return T(0);
408 }
409
410 template <class T>
raise_denorm_error(const char *,const char *,const T & val,const::boost::math::policies::denorm_error<::boost::math::policies::ignore_error> &)411 inline BOOST_MATH_CONSTEXPR T raise_denorm_error(
412 const char* ,
413 const char* ,
414 const T& val,
415 const ::boost::math::policies::denorm_error< ::boost::math::policies::ignore_error>&) BOOST_MATH_NOEXCEPT(T)
416 {
417 // This may or may not do the right thing, but the user asked for the error
418 // to be ignored so here we go anyway:
419 return val;
420 }
421
422 template <class T>
raise_denorm_error(const char *,const char *,const T & val,const::boost::math::policies::denorm_error<::boost::math::policies::errno_on_error> &)423 inline T raise_denorm_error(
424 const char* ,
425 const char* ,
426 const T& val,
427 const ::boost::math::policies::denorm_error< ::boost::math::policies::errno_on_error>&) BOOST_MATH_NOEXCEPT(T)
428 {
429 errno = ERANGE;
430 // This may or may not do the right thing, but the user asked for the error
431 // to be silent so here we go anyway:
432 return val;
433 }
434
435 template <class T>
raise_denorm_error(const char * function,const char * message,const T & val,const::boost::math::policies::denorm_error<::boost::math::policies::user_error> &)436 inline T raise_denorm_error(
437 const char* function,
438 const char* message,
439 const T& val,
440 const ::boost::math::policies::denorm_error< ::boost::math::policies::user_error>&)
441 {
442 return user_denorm_error(function, message, val);
443 }
444
445 template <class T>
raise_evaluation_error(const char * function,const char * message,const T & val,const::boost::math::policies::evaluation_error<::boost::math::policies::throw_on_error> &)446 inline T raise_evaluation_error(
447 const char* function,
448 const char* message,
449 const T& val,
450 const ::boost::math::policies::evaluation_error< ::boost::math::policies::throw_on_error>&)
451 {
452 raise_error<boost::math::evaluation_error, T>(function, message, val);
453 // we never get here:
454 return T(0);
455 }
456
457 template <class T>
raise_evaluation_error(const char *,const char *,const T & val,const::boost::math::policies::evaluation_error<::boost::math::policies::ignore_error> &)458 inline BOOST_MATH_CONSTEXPR T raise_evaluation_error(
459 const char* ,
460 const char* ,
461 const T& val,
462 const ::boost::math::policies::evaluation_error< ::boost::math::policies::ignore_error>&) BOOST_MATH_NOEXCEPT(T)
463 {
464 // This may or may not do the right thing, but the user asked for the error
465 // to be ignored so here we go anyway:
466 return val;
467 }
468
469 template <class T>
raise_evaluation_error(const char *,const char *,const T & val,const::boost::math::policies::evaluation_error<::boost::math::policies::errno_on_error> &)470 inline T raise_evaluation_error(
471 const char* ,
472 const char* ,
473 const T& val,
474 const ::boost::math::policies::evaluation_error< ::boost::math::policies::errno_on_error>&) BOOST_MATH_NOEXCEPT(T)
475 {
476 errno = EDOM;
477 // This may or may not do the right thing, but the user asked for the error
478 // to be silent so here we go anyway:
479 return val;
480 }
481
482 template <class T>
raise_evaluation_error(const char * function,const char * message,const T & val,const::boost::math::policies::evaluation_error<::boost::math::policies::user_error> &)483 inline T raise_evaluation_error(
484 const char* function,
485 const char* message,
486 const T& val,
487 const ::boost::math::policies::evaluation_error< ::boost::math::policies::user_error>&)
488 {
489 return user_evaluation_error(function, message, val);
490 }
491
492 template <class T, class TargetType>
raise_rounding_error(const char * function,const char * message,const T & val,const TargetType &,const::boost::math::policies::rounding_error<::boost::math::policies::throw_on_error> &)493 inline TargetType raise_rounding_error(
494 const char* function,
495 const char* message,
496 const T& val,
497 const TargetType&,
498 const ::boost::math::policies::rounding_error< ::boost::math::policies::throw_on_error>&)
499 {
500 raise_error<boost::math::rounding_error, T>(function, message, val);
501 // we never get here:
502 return TargetType(0);
503 }
504
505 template <class T, class TargetType>
raise_rounding_error(const char *,const char *,const T & val,const TargetType &,const::boost::math::policies::rounding_error<::boost::math::policies::ignore_error> &)506 inline BOOST_MATH_CONSTEXPR TargetType raise_rounding_error(
507 const char* ,
508 const char* ,
509 const T& val,
510 const TargetType&,
511 const ::boost::math::policies::rounding_error< ::boost::math::policies::ignore_error>&) BOOST_MATH_NOEXCEPT(T)
512 {
513 // This may or may not do the right thing, but the user asked for the error
514 // to be ignored so here we go anyway:
515 BOOST_STATIC_ASSERT(std::numeric_limits<TargetType>::is_specialized);
516 return val > 0 ? (std::numeric_limits<TargetType>::max)() : (std::numeric_limits<TargetType>::is_integer ? (std::numeric_limits<TargetType>::min)() : -(std::numeric_limits<TargetType>::max)());
517 }
518
519 template <class T, class TargetType>
raise_rounding_error(const char *,const char *,const T & val,const TargetType &,const::boost::math::policies::rounding_error<::boost::math::policies::errno_on_error> &)520 inline TargetType raise_rounding_error(
521 const char* ,
522 const char* ,
523 const T& val,
524 const TargetType&,
525 const ::boost::math::policies::rounding_error< ::boost::math::policies::errno_on_error>&) BOOST_MATH_NOEXCEPT(T)
526 {
527 errno = ERANGE;
528 // This may or may not do the right thing, but the user asked for the error
529 // to be silent so here we go anyway:
530 BOOST_STATIC_ASSERT(std::numeric_limits<TargetType>::is_specialized);
531 return val > 0 ? (std::numeric_limits<TargetType>::max)() : (std::numeric_limits<TargetType>::is_integer ? (std::numeric_limits<TargetType>::min)() : -(std::numeric_limits<TargetType>::max)());
532 }
533
534 template <class T>
raise_rounding_error(const char *,const char *,const T & val,const T &,const::boost::math::policies::rounding_error<::boost::math::policies::errno_on_error> &)535 inline T raise_rounding_error(
536 const char* ,
537 const char* ,
538 const T& val,
539 const T&,
540 const ::boost::math::policies::rounding_error< ::boost::math::policies::errno_on_error>&) BOOST_MATH_NOEXCEPT(T)
541 {
542 errno = ERANGE;
543 // This may or may not do the right thing, but the user asked for the error
544 // to be silent so here we go anyway:
545 return val > 0 ? boost::math::tools::max_value<T>() : -boost::math::tools::max_value<T>();
546 }
547
548 template <class T, class TargetType>
raise_rounding_error(const char * function,const char * message,const T & val,const TargetType & t,const::boost::math::policies::rounding_error<::boost::math::policies::user_error> &)549 inline TargetType raise_rounding_error(
550 const char* function,
551 const char* message,
552 const T& val,
553 const TargetType& t,
554 const ::boost::math::policies::rounding_error< ::boost::math::policies::user_error>&)
555 {
556 return user_rounding_error(function, message, val, t);
557 }
558
559 template <class T, class R>
raise_indeterminate_result_error(const char * function,const char * message,const T & val,const R &,const::boost::math::policies::indeterminate_result_error<::boost::math::policies::throw_on_error> &)560 inline T raise_indeterminate_result_error(
561 const char* function,
562 const char* message,
563 const T& val,
564 const R& ,
565 const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::throw_on_error>&)
566 {
567 raise_error<std::domain_error, T>(function, message, val);
568 // we never get here:
569 return std::numeric_limits<T>::quiet_NaN();
570 }
571
572 template <class T, class R>
raise_indeterminate_result_error(const char *,const char *,const T &,const R & result,const::boost::math::policies::indeterminate_result_error<::boost::math::policies::ignore_error> &)573 inline BOOST_MATH_CONSTEXPR T raise_indeterminate_result_error(
574 const char* ,
575 const char* ,
576 const T& ,
577 const R& result,
578 const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::ignore_error>&) BOOST_MATH_NOEXCEPT(T)
579 {
580 // This may or may not do the right thing, but the user asked for the error
581 // to be ignored so here we go anyway:
582 return result;
583 }
584
585 template <class T, class R>
raise_indeterminate_result_error(const char *,const char *,const T &,const R & result,const::boost::math::policies::indeterminate_result_error<::boost::math::policies::errno_on_error> &)586 inline T raise_indeterminate_result_error(
587 const char* ,
588 const char* ,
589 const T& ,
590 const R& result,
591 const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::errno_on_error>&)
592 {
593 errno = EDOM;
594 // This may or may not do the right thing, but the user asked for the error
595 // to be silent so here we go anyway:
596 return result;
597 }
598
599 template <class T, class R>
raise_indeterminate_result_error(const char * function,const char * message,const T & val,const R &,const::boost::math::policies::indeterminate_result_error<::boost::math::policies::user_error> &)600 inline T raise_indeterminate_result_error(
601 const char* function,
602 const char* message,
603 const T& val,
604 const R& ,
605 const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::user_error>&)
606 {
607 return user_indeterminate_result_error(function, message, val);
608 }
609
610 } // namespace detail
611
612 template <class T, class Policy>
raise_domain_error(const char * function,const char * message,const T & val,const Policy &)613 inline BOOST_MATH_CONSTEXPR T raise_domain_error(const char* function, const char* message, const T& val, const Policy&) BOOST_NOEXCEPT_IF(is_noexcept_error_policy<Policy>::value && BOOST_MATH_IS_FLOAT(T))
614 {
615 typedef typename Policy::domain_error_type policy_type;
616 return detail::raise_domain_error(
617 function, message ? message : "Domain Error evaluating function at %1%",
618 val, policy_type());
619 }
620
621 template <class T, class Policy>
raise_pole_error(const char * function,const char * message,const T & val,const Policy &)622 inline BOOST_MATH_CONSTEXPR T raise_pole_error(const char* function, const char* message, const T& val, const Policy&) BOOST_NOEXCEPT_IF(is_noexcept_error_policy<Policy>::value && BOOST_MATH_IS_FLOAT(T))
623 {
624 typedef typename Policy::pole_error_type policy_type;
625 return detail::raise_pole_error(
626 function, message ? message : "Evaluation of function at pole %1%",
627 val, policy_type());
628 }
629
630 template <class T, class Policy>
raise_overflow_error(const char * function,const char * message,const Policy &)631 inline BOOST_MATH_CONSTEXPR T raise_overflow_error(const char* function, const char* message, const Policy&) BOOST_NOEXCEPT_IF(is_noexcept_error_policy<Policy>::value && BOOST_MATH_IS_FLOAT(T))
632 {
633 typedef typename Policy::overflow_error_type policy_type;
634 return detail::raise_overflow_error<T>(
635 function, message ? message : "Overflow Error",
636 policy_type());
637 }
638
639 template <class T, class Policy>
raise_overflow_error(const char * function,const char * message,const T & val,const Policy &)640 inline BOOST_MATH_CONSTEXPR T raise_overflow_error(const char* function, const char* message, const T& val, const Policy&) BOOST_NOEXCEPT_IF(is_noexcept_error_policy<Policy>::value && BOOST_MATH_IS_FLOAT(T))
641 {
642 typedef typename Policy::overflow_error_type policy_type;
643 return detail::raise_overflow_error(
644 function, message ? message : "Overflow evaluating function at %1%",
645 val, policy_type());
646 }
647
648 template <class T, class Policy>
raise_underflow_error(const char * function,const char * message,const Policy &)649 inline BOOST_MATH_CONSTEXPR T raise_underflow_error(const char* function, const char* message, const Policy&) BOOST_NOEXCEPT_IF(is_noexcept_error_policy<Policy>::value && BOOST_MATH_IS_FLOAT(T))
650 {
651 typedef typename Policy::underflow_error_type policy_type;
652 return detail::raise_underflow_error<T>(
653 function, message ? message : "Underflow Error",
654 policy_type());
655 }
656
657 template <class T, class Policy>
raise_denorm_error(const char * function,const char * message,const T & val,const Policy &)658 inline BOOST_MATH_CONSTEXPR T raise_denorm_error(const char* function, const char* message, const T& val, const Policy&) BOOST_NOEXCEPT_IF(is_noexcept_error_policy<Policy>::value && BOOST_MATH_IS_FLOAT(T))
659 {
660 typedef typename Policy::denorm_error_type policy_type;
661 return detail::raise_denorm_error<T>(
662 function, message ? message : "Denorm Error",
663 val,
664 policy_type());
665 }
666
667 template <class T, class Policy>
raise_evaluation_error(const char * function,const char * message,const T & val,const Policy &)668 inline BOOST_MATH_CONSTEXPR T raise_evaluation_error(const char* function, const char* message, const T& val, const Policy&) BOOST_NOEXCEPT_IF(is_noexcept_error_policy<Policy>::value && BOOST_MATH_IS_FLOAT(T))
669 {
670 typedef typename Policy::evaluation_error_type policy_type;
671 return detail::raise_evaluation_error(
672 function, message ? message : "Internal Evaluation Error, best value so far was %1%",
673 val, policy_type());
674 }
675
676 template <class T, class TargetType, class Policy>
raise_rounding_error(const char * function,const char * message,const T & val,const TargetType & t,const Policy &)677 inline BOOST_MATH_CONSTEXPR TargetType raise_rounding_error(const char* function, const char* message, const T& val, const TargetType& t, const Policy&) BOOST_NOEXCEPT_IF(is_noexcept_error_policy<Policy>::value && BOOST_MATH_IS_FLOAT(T))
678 {
679 typedef typename Policy::rounding_error_type policy_type;
680 return detail::raise_rounding_error(
681 function, message ? message : "Value %1% can not be represented in the target integer type.",
682 val, t, policy_type());
683 }
684
685 template <class T, class R, class Policy>
raise_indeterminate_result_error(const char * function,const char * message,const T & val,const R & result,const Policy &)686 inline BOOST_MATH_CONSTEXPR T raise_indeterminate_result_error(const char* function, const char* message, const T& val, const R& result, const Policy&) BOOST_NOEXCEPT_IF(is_noexcept_error_policy<Policy>::value && BOOST_MATH_IS_FLOAT(T))
687 {
688 typedef typename Policy::indeterminate_result_error_type policy_type;
689 return detail::raise_indeterminate_result_error(
690 function, message ? message : "Indeterminate result with value %1%",
691 val, result, policy_type());
692 }
693
694 //
695 // checked_narrowing_cast:
696 //
697 namespace detail
698 {
699
700 template <class R, class T, class Policy>
check_overflow(T val,R * result,const char * function,const Policy & pol)701 inline bool check_overflow(T val, R* result, const char* function, const Policy& pol) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(R) && BOOST_MATH_IS_FLOAT(T) && (Policy::value != throw_on_error) && (Policy::value != user_error))
702 {
703 BOOST_MATH_STD_USING
704 if(fabs(val) > tools::max_value<R>())
705 {
706 boost::math::policies::detail::raise_overflow_error<R>(function, 0, pol);
707 *result = static_cast<R>(val);
708 return true;
709 }
710 return false;
711 }
712 template <class R, class T, class Policy>
check_overflow(std::complex<T> val,R * result,const char * function,const Policy & pol)713 inline bool check_overflow(std::complex<T> val, R* result, const char* function, const Policy& pol) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(R) && BOOST_MATH_IS_FLOAT(T) && (Policy::value != throw_on_error) && (Policy::value != user_error))
714 {
715 typedef typename R::value_type r_type;
716 r_type re, im;
717 bool r = check_overflow<r_type>(val.real(), &re, function, pol);
718 r = check_overflow<r_type>(val.imag(), &im, function, pol) || r;
719 *result = R(re, im);
720 return r;
721 }
722 template <class R, class T, class Policy>
check_underflow(T val,R * result,const char * function,const Policy & pol)723 inline bool check_underflow(T val, R* result, const char* function, const Policy& pol) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(R) && BOOST_MATH_IS_FLOAT(T) && (Policy::value != throw_on_error) && (Policy::value != user_error))
724 {
725 if((val != 0) && (static_cast<R>(val) == 0))
726 {
727 *result = static_cast<R>(boost::math::policies::detail::raise_underflow_error<R>(function, 0, pol));
728 return true;
729 }
730 return false;
731 }
732 template <class R, class T, class Policy>
check_underflow(std::complex<T> val,R * result,const char * function,const Policy & pol)733 inline bool check_underflow(std::complex<T> val, R* result, const char* function, const Policy& pol) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(R) && BOOST_MATH_IS_FLOAT(T) && (Policy::value != throw_on_error) && (Policy::value != user_error))
734 {
735 typedef typename R::value_type r_type;
736 r_type re, im;
737 bool r = check_underflow<r_type>(val.real(), &re, function, pol);
738 r = check_underflow<r_type>(val.imag(), &im, function, pol) || r;
739 *result = R(re, im);
740 return r;
741 }
742 template <class R, class T, class Policy>
check_denorm(T val,R * result,const char * function,const Policy & pol)743 inline bool check_denorm(T val, R* result, const char* function, const Policy& pol) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(R) && BOOST_MATH_IS_FLOAT(T) && (Policy::value != throw_on_error) && (Policy::value != user_error))
744 {
745 BOOST_MATH_STD_USING
746 if((fabs(val) < static_cast<T>(tools::min_value<R>())) && (static_cast<R>(val) != 0))
747 {
748 *result = static_cast<R>(boost::math::policies::detail::raise_denorm_error<R>(function, 0, static_cast<R>(val), pol));
749 return true;
750 }
751 return false;
752 }
753 template <class R, class T, class Policy>
check_denorm(std::complex<T> val,R * result,const char * function,const Policy & pol)754 inline bool check_denorm(std::complex<T> val, R* result, const char* function, const Policy& pol) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(R) && BOOST_MATH_IS_FLOAT(T) && (Policy::value != throw_on_error) && (Policy::value != user_error))
755 {
756 typedef typename R::value_type r_type;
757 r_type re, im;
758 bool r = check_denorm<r_type>(val.real(), &re, function, pol);
759 r = check_denorm<r_type>(val.imag(), &im, function, pol) || r;
760 *result = R(re, im);
761 return r;
762 }
763
764 // Default instantiations with ignore_error policy.
765 template <class R, class T>
check_overflow(T,R *,const char *,const overflow_error<ignore_error> &)766 inline BOOST_MATH_CONSTEXPR bool check_overflow(T /* val */, R* /* result */, const char* /* function */, const overflow_error<ignore_error>&) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(R) && BOOST_MATH_IS_FLOAT(T))
767 { return false; }
768 template <class R, class T>
check_overflow(std::complex<T>,R *,const char *,const overflow_error<ignore_error> &)769 inline BOOST_MATH_CONSTEXPR bool check_overflow(std::complex<T> /* val */, R* /* result */, const char* /* function */, const overflow_error<ignore_error>&) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(R) && BOOST_MATH_IS_FLOAT(T))
770 { return false; }
771 template <class R, class T>
check_underflow(T,R *,const char *,const underflow_error<ignore_error> &)772 inline BOOST_MATH_CONSTEXPR bool check_underflow(T /* val */, R* /* result */, const char* /* function */, const underflow_error<ignore_error>&) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(R) && BOOST_MATH_IS_FLOAT(T))
773 { return false; }
774 template <class R, class T>
check_underflow(std::complex<T>,R *,const char *,const underflow_error<ignore_error> &)775 inline BOOST_MATH_CONSTEXPR bool check_underflow(std::complex<T> /* val */, R* /* result */, const char* /* function */, const underflow_error<ignore_error>&) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(R) && BOOST_MATH_IS_FLOAT(T))
776 { return false; }
777 template <class R, class T>
check_denorm(T,R *,const char *,const denorm_error<ignore_error> &)778 inline BOOST_MATH_CONSTEXPR bool check_denorm(T /* val */, R* /* result*/, const char* /* function */, const denorm_error<ignore_error>&) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(R) && BOOST_MATH_IS_FLOAT(T))
779 { return false; }
780 template <class R, class T>
check_denorm(std::complex<T>,R *,const char *,const denorm_error<ignore_error> &)781 inline BOOST_MATH_CONSTEXPR bool check_denorm(std::complex<T> /* val */, R* /* result*/, const char* /* function */, const denorm_error<ignore_error>&) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(R) && BOOST_MATH_IS_FLOAT(T))
782 { return false; }
783
784 } // namespace detail
785
786 template <class R, class Policy, class T>
checked_narrowing_cast(T val,const char * function)787 inline R checked_narrowing_cast(T val, const char* function) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(R) && BOOST_MATH_IS_FLOAT(T) && is_noexcept_error_policy<Policy>::value)
788 {
789 typedef typename Policy::overflow_error_type overflow_type;
790 typedef typename Policy::underflow_error_type underflow_type;
791 typedef typename Policy::denorm_error_type denorm_type;
792 //
793 // Most of what follows will evaluate to a no-op:
794 //
795 R result = 0;
796 if(detail::check_overflow<R>(val, &result, function, overflow_type()))
797 return result;
798 if(detail::check_underflow<R>(val, &result, function, underflow_type()))
799 return result;
800 if(detail::check_denorm<R>(val, &result, function, denorm_type()))
801 return result;
802
803 return static_cast<R>(val);
804 }
805
806 template <class T, class Policy>
check_series_iterations(const char * function,boost::uintmax_t max_iter,const Policy & pol)807 inline void check_series_iterations(const char* function, boost::uintmax_t max_iter, const Policy& pol) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(T) && is_noexcept_error_policy<Policy>::value)
808 {
809 if(max_iter >= policies::get_max_series_iterations<Policy>())
810 raise_evaluation_error<T>(
811 function,
812 "Series evaluation exceeded %1% iterations, giving up now.", static_cast<T>(static_cast<double>(max_iter)), pol);
813 }
814
815 template <class T, class Policy>
check_root_iterations(const char * function,boost::uintmax_t max_iter,const Policy & pol)816 inline void check_root_iterations(const char* function, boost::uintmax_t max_iter, const Policy& pol) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(T) && is_noexcept_error_policy<Policy>::value)
817 {
818 if(max_iter >= policies::get_max_root_iterations<Policy>())
819 raise_evaluation_error<T>(
820 function,
821 "Root finding evaluation exceeded %1% iterations, giving up now.", static_cast<T>(static_cast<double>(max_iter)), pol);
822 }
823
824 } //namespace policies
825
826 namespace detail{
827
828 //
829 // Simple helper function to assist in returning a pair from a single value,
830 // that value usually comes from one of the error handlers above:
831 //
832 template <class T>
pair_from_single(const T & val)833 std::pair<T, T> pair_from_single(const T& val) BOOST_MATH_NOEXCEPT(T)
834 {
835 return std::make_pair(val, val);
836 }
837
838 }
839
840 #ifdef BOOST_MSVC
841 # pragma warning(pop)
842 #endif
843
844 }} // namespaces boost/math
845
846 #endif // BOOST_MATH_POLICY_ERROR_HANDLING_HPP
847
848