1 // Copyright John Maddock 2007.
2 // Copyright Paul A. Bristow 2007.
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)
8 #ifndef BOOST_MATH_POLICY_ERROR_HANDLING_HPP
9 #define BOOST_MATH_POLICY_ERROR_HANDLING_HPP
15 #include <boost/config/no_tr1/cmath.hpp>
17 #include <boost/math/tools/config.hpp>
18 #include <boost/math/policies/policy.hpp>
19 #include <boost/math/tools/precision.hpp>
20 #include <boost/cstdint.hpp>
22 # pragma warning(push) // Quiet warnings in boost/format.hpp
23 # pragma warning(disable: 4996) // _SCL_SECURE_NO_DEPRECATE
24 # pragma warning(disable: 4512) // assignment operator could not be generated.
25 // And warnings in error handling:
26 # pragma warning(disable: 4702) // unreachable code
27 // Note that this only occurs when the compiler can deduce code is unreachable,
28 // for example when policy macros are used to ignore errors rather than throw.
30 #include <boost/format.hpp>
32 namespace boost{ namespace math{
34 class evaluation_error : public std::runtime_error
37 evaluation_error(const std::string& s) : std::runtime_error(s){}
40 class rounding_error : public std::runtime_error
43 rounding_error(const std::string& s) : std::runtime_error(s){}
48 // Forward declarations of user error handlers,
49 // it's up to the user to provide the definition of these:
52 T user_domain_error(const char* function, const char* message, const T& val);
54 T user_pole_error(const char* function, const char* message, const T& val);
56 T user_overflow_error(const char* function, const char* message, const T& val);
58 T user_underflow_error(const char* function, const char* message, const T& val);
60 T user_denorm_error(const char* function, const char* message, const T& val);
62 T user_evaluation_error(const char* function, const char* message, const T& val);
64 T user_rounding_error(const char* function, const char* message, const T& val);
66 T user_indeterminate_result_error(const char* function, const char* message, const T& val);
71 // Helper function to avoid binding rvalue to non-const-reference,
72 // in other words a warning suppression mechansim:
74 template <class Formatter, class Group>
75 inline std::string do_format(Formatter f, const Group& g)
80 template <class E, class T>
81 void raise_error(const char* function, const char* message)
84 function = "Unknown function operating on type %1%";
86 message = "Cause unknown";
88 std::string msg("Error in function ");
89 msg += (boost::format(function) % typeid(T).name()).str();
94 boost::throw_exception(e);
97 template <class E, class T>
98 void raise_error(const char* function, const char* message, const T& val)
101 function = "Unknown function operating on type %1%";
103 message = "Cause unknown: error caused by bad argument with value %1%";
105 std::string msg("Error in function ");
106 msg += (boost::format(function) % typeid(T).name()).str();
110 int prec = 2 + (boost::math::policies::digits<T, boost::math::policies::policy<> >() * 30103UL) / 100000UL;
111 msg = do_format(boost::format(msg), boost::io::group(std::setprecision(prec), val));
114 boost::throw_exception(e);
118 inline T raise_domain_error(
119 const char* function,
122 const ::boost::math::policies::domain_error< ::boost::math::policies::throw_on_error>&)
124 raise_error<std::domain_error, T>(function, message, val);
125 // we never get here:
126 return std::numeric_limits<T>::quiet_NaN();
130 inline T raise_domain_error(
134 const ::boost::math::policies::domain_error< ::boost::math::policies::ignore_error>&)
136 // This may or may not do the right thing, but the user asked for the error
137 // to be ignored so here we go anyway:
138 return std::numeric_limits<T>::quiet_NaN();
142 inline T raise_domain_error(
146 const ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>&)
149 // This may or may not do the right thing, but the user asked for the error
150 // to be silent so here we go anyway:
151 return std::numeric_limits<T>::quiet_NaN();
155 inline T raise_domain_error(
156 const char* function,
159 const ::boost::math::policies::domain_error< ::boost::math::policies::user_error>&)
161 return user_domain_error(function, message, val);
165 inline T raise_pole_error(
166 const char* function,
169 const ::boost::math::policies::pole_error< ::boost::math::policies::throw_on_error>&)
171 return boost::math::policies::detail::raise_domain_error(function, message, val, ::boost::math::policies::domain_error< ::boost::math::policies::throw_on_error>());
175 inline T raise_pole_error(
176 const char* function,
179 const ::boost::math::policies::pole_error< ::boost::math::policies::ignore_error>&)
181 return ::boost::math::policies::detail::raise_domain_error(function, message, val, ::boost::math::policies::domain_error< ::boost::math::policies::ignore_error>());
185 inline T raise_pole_error(
186 const char* function,
189 const ::boost::math::policies::pole_error< ::boost::math::policies::errno_on_error>&)
191 return ::boost::math::policies::detail::raise_domain_error(function, message, val, ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>());
195 inline T raise_pole_error(
196 const char* function,
199 const ::boost::math::policies::pole_error< ::boost::math::policies::user_error>&)
201 return user_pole_error(function, message, val);
205 inline T raise_overflow_error(
206 const char* function,
208 const ::boost::math::policies::overflow_error< ::boost::math::policies::throw_on_error>&)
210 raise_error<std::overflow_error, T>(function, message ? message : "numeric overflow");
211 // we never get here:
212 return std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : boost::math::tools::max_value<T>();
216 inline T raise_overflow_error(
219 const ::boost::math::policies::overflow_error< ::boost::math::policies::ignore_error>&)
221 // This may or may not do the right thing, but the user asked for the error
222 // to be ignored so here we go anyway:
223 return std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : boost::math::tools::max_value<T>();
227 inline T raise_overflow_error(
230 const ::boost::math::policies::overflow_error< ::boost::math::policies::errno_on_error>&)
233 // This may or may not do the right thing, but the user asked for the error
234 // to be silent so here we go anyway:
235 return std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : boost::math::tools::max_value<T>();
239 inline T raise_overflow_error(
240 const char* function,
242 const ::boost::math::policies::overflow_error< ::boost::math::policies::user_error>&)
244 return user_overflow_error(function, message, std::numeric_limits<T>::infinity());
248 inline T raise_underflow_error(
249 const char* function,
251 const ::boost::math::policies::underflow_error< ::boost::math::policies::throw_on_error>&)
253 raise_error<std::underflow_error, T>(function, message ? message : "numeric underflow");
254 // we never get here:
259 inline T raise_underflow_error(
262 const ::boost::math::policies::underflow_error< ::boost::math::policies::ignore_error>&)
264 // This may or may not do the right thing, but the user asked for the error
265 // to be ignored so here we go anyway:
270 inline T raise_underflow_error(
271 const char* /* function */,
272 const char* /* message */,
273 const ::boost::math::policies::underflow_error< ::boost::math::policies::errno_on_error>&)
276 // This may or may not do the right thing, but the user asked for the error
277 // to be silent so here we go anyway:
282 inline T raise_underflow_error(
283 const char* function,
285 const ::boost::math::policies::underflow_error< ::boost::math::policies::user_error>&)
287 return user_underflow_error(function, message, T(0));
291 inline T raise_denorm_error(
292 const char* function,
295 const ::boost::math::policies::denorm_error< ::boost::math::policies::throw_on_error>&)
297 raise_error<std::underflow_error, T>(function, message ? message : "denormalised result");
298 // we never get here:
303 inline T raise_denorm_error(
307 const ::boost::math::policies::denorm_error< ::boost::math::policies::ignore_error>&)
309 // This may or may not do the right thing, but the user asked for the error
310 // to be ignored so here we go anyway:
315 inline T raise_denorm_error(
319 const ::boost::math::policies::denorm_error< ::boost::math::policies::errno_on_error>&)
322 // This may or may not do the right thing, but the user asked for the error
323 // to be silent so here we go anyway:
328 inline T raise_denorm_error(
329 const char* function,
332 const ::boost::math::policies::denorm_error< ::boost::math::policies::user_error>&)
334 return user_denorm_error(function, message, val);
338 inline T raise_evaluation_error(
339 const char* function,
342 const ::boost::math::policies::evaluation_error< ::boost::math::policies::throw_on_error>&)
344 raise_error<boost::math::evaluation_error, T>(function, message, val);
345 // we never get here:
350 inline T raise_evaluation_error(
354 const ::boost::math::policies::evaluation_error< ::boost::math::policies::ignore_error>&)
356 // This may or may not do the right thing, but the user asked for the error
357 // to be ignored so here we go anyway:
362 inline T raise_evaluation_error(
366 const ::boost::math::policies::evaluation_error< ::boost::math::policies::errno_on_error>&)
369 // This may or may not do the right thing, but the user asked for the error
370 // to be silent so here we go anyway:
375 inline T raise_evaluation_error(
376 const char* function,
379 const ::boost::math::policies::evaluation_error< ::boost::math::policies::user_error>&)
381 return user_evaluation_error(function, message, val);
385 inline T raise_rounding_error(
386 const char* function,
389 const ::boost::math::policies::rounding_error< ::boost::math::policies::throw_on_error>&)
391 raise_error<boost::math::rounding_error, T>(function, message, val);
392 // we never get here:
397 inline T raise_rounding_error(
401 const ::boost::math::policies::rounding_error< ::boost::math::policies::ignore_error>&)
403 // This may or may not do the right thing, but the user asked for the error
404 // to be ignored so here we go anyway:
409 inline T raise_rounding_error(
413 const ::boost::math::policies::rounding_error< ::boost::math::policies::errno_on_error>&)
416 // This may or may not do the right thing, but the user asked for the error
417 // to be silent so here we go anyway:
422 inline T raise_rounding_error(
423 const char* function,
426 const ::boost::math::policies::rounding_error< ::boost::math::policies::user_error>&)
428 return user_rounding_error(function, message, val);
431 template <class T, class R>
432 inline T raise_indeterminate_result_error(
433 const char* function,
437 const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::throw_on_error>&)
439 raise_error<std::domain_error, T>(function, message, val);
440 // we never get here:
441 return std::numeric_limits<T>::quiet_NaN();
444 template <class T, class R>
445 inline T raise_indeterminate_result_error(
450 const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::ignore_error>&)
452 // This may or may not do the right thing, but the user asked for the error
453 // to be ignored so here we go anyway:
457 template <class T, class R>
458 inline T raise_indeterminate_result_error(
463 const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::errno_on_error>&)
466 // This may or may not do the right thing, but the user asked for the error
467 // to be silent so here we go anyway:
471 template <class T, class R>
472 inline T raise_indeterminate_result_error(
473 const char* function,
477 const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::user_error>&)
479 return user_indeterminate_result_error(function, message, val);
482 } // namespace detail
484 template <class T, class Policy>
485 inline T raise_domain_error(const char* function, const char* message, const T& val, const Policy&)
487 typedef typename Policy::domain_error_type policy_type;
488 return detail::raise_domain_error(
489 function, message ? message : "Domain Error evaluating function at %1%",
493 template <class T, class Policy>
494 inline T raise_pole_error(const char* function, const char* message, const T& val, const Policy&)
496 typedef typename Policy::pole_error_type policy_type;
497 return detail::raise_pole_error(
498 function, message ? message : "Evaluation of function at pole %1%",
502 template <class T, class Policy>
503 inline T raise_overflow_error(const char* function, const char* message, const Policy&)
505 typedef typename Policy::overflow_error_type policy_type;
506 return detail::raise_overflow_error<T>(
507 function, message ? message : "Overflow Error",
511 template <class T, class Policy>
512 inline T raise_underflow_error(const char* function, const char* message, const Policy&)
514 typedef typename Policy::underflow_error_type policy_type;
515 return detail::raise_underflow_error<T>(
516 function, message ? message : "Underflow Error",
520 template <class T, class Policy>
521 inline T raise_denorm_error(const char* function, const char* message, const T& val, const Policy&)
523 typedef typename Policy::denorm_error_type policy_type;
524 return detail::raise_denorm_error<T>(
525 function, message ? message : "Denorm Error",
530 template <class T, class Policy>
531 inline T raise_evaluation_error(const char* function, const char* message, const T& val, const Policy&)
533 typedef typename Policy::evaluation_error_type policy_type;
534 return detail::raise_evaluation_error(
535 function, message ? message : "Internal Evaluation Error, best value so far was %1%",
539 template <class T, class Policy>
540 inline T raise_rounding_error(const char* function, const char* message, const T& val, const Policy&)
542 typedef typename Policy::rounding_error_type policy_type;
543 return detail::raise_rounding_error(
544 function, message ? message : "Value %1% can not be represented in the target integer type.",
548 template <class T, class R, class Policy>
549 inline T raise_indeterminate_result_error(const char* function, const char* message, const T& val, const R& result, const Policy&)
551 typedef typename Policy::indeterminate_result_error_type policy_type;
552 return detail::raise_indeterminate_result_error(
553 function, message ? message : "Indeterminate result with value %1%",
554 val, result, policy_type());
558 // checked_narrowing_cast:
563 template <class R, class T, class Policy>
564 inline bool check_overflow(T val, R* result, const char* function, const Policy& pol)
567 if(fabs(val) > tools::max_value<R>())
569 *result = static_cast<R>(boost::math::policies::detail::raise_overflow_error<R>(function, 0, pol));
574 template <class R, class T, class Policy>
575 inline bool check_underflow(T val, R* result, const char* function, const Policy& pol)
577 if((val != 0) && (static_cast<R>(val) == 0))
579 *result = static_cast<R>(boost::math::policies::detail::raise_underflow_error<R>(function, 0, pol));
584 template <class R, class T, class Policy>
585 inline bool check_denorm(T val, R* result, const char* function, const Policy& pol)
588 if((fabs(val) < static_cast<T>(tools::min_value<R>())) && (static_cast<R>(val) != 0))
590 *result = static_cast<R>(boost::math::policies::detail::raise_denorm_error<R>(function, 0, static_cast<R>(val), pol));
596 // Default instantiations with ignore_error policy.
597 template <class R, class T>
598 inline bool check_overflow(T /* val */, R* /* result */, const char* /* function */, const overflow_error<ignore_error>&){ return false; }
599 template <class R, class T>
600 inline bool check_underflow(T /* val */, R* /* result */, const char* /* function */, const underflow_error<ignore_error>&){ return false; }
601 template <class R, class T>
602 inline bool check_denorm(T /* val */, R* /* result*/, const char* /* function */, const denorm_error<ignore_error>&){ return false; }
604 } // namespace detail
606 template <class R, class Policy, class T>
607 inline R checked_narrowing_cast(T val, const char* function)
609 typedef typename Policy::overflow_error_type overflow_type;
610 typedef typename Policy::underflow_error_type underflow_type;
611 typedef typename Policy::denorm_error_type denorm_type;
613 // Most of what follows will evaluate to a no-op:
616 if(detail::check_overflow<R>(val, &result, function, overflow_type()))
618 if(detail::check_underflow<R>(val, &result, function, underflow_type()))
620 if(detail::check_denorm<R>(val, &result, function, denorm_type()))
623 return static_cast<R>(val);
626 template <class Policy>
627 inline void check_series_iterations(const char* function, boost::uintmax_t max_iter, const Policy& pol)
629 if(max_iter >= policies::get_max_series_iterations<Policy>())
630 raise_evaluation_error<boost::uintmax_t>(
632 "Series evaluation exceeded %1% iterations, giving up now.", max_iter, pol);
635 template <class Policy>
636 inline void check_root_iterations(const char* function, boost::uintmax_t max_iter, const Policy& pol)
638 if(max_iter >= policies::get_max_root_iterations<Policy>())
639 raise_evaluation_error<boost::uintmax_t>(
641 "Root finding evaluation exceeded %1% iterations, giving up now.", max_iter, pol);
644 } //namespace policies
647 # pragma warning(pop)
650 }} // namespaces boost/math
652 #endif // BOOST_MATH_POLICY_ERROR_HANDLING_HPP