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/complex.hpp>
16 #include <boost/config/no_tr1/cmath.hpp>
18 #include <boost/math/tools/config.hpp>
19 #include <boost/math/policies/policy.hpp>
20 #include <boost/math/tools/precision.hpp>
21 #include <boost/cstdint.hpp>
23 # pragma warning(push) // Quiet warnings in boost/format.hpp
24 # pragma warning(disable: 4996) // _SCL_SECURE_NO_DEPRECATE
25 # pragma warning(disable: 4512) // assignment operator could not be generated.
26 // And warnings in error handling:
27 # pragma warning(disable: 4702) // unreachable code.
28 // Note that this only occurs when the compiler can deduce code is unreachable,
29 // for example when policy macros are used to ignore errors rather than throw.
31 #include <boost/format.hpp>
33 namespace boost{ namespace math{
35 class evaluation_error : public std::runtime_error
38 evaluation_error(const std::string& s) : std::runtime_error(s){}
41 class rounding_error : public std::runtime_error
44 rounding_error(const std::string& s) : std::runtime_error(s){}
49 // Forward declarations of user error handlers,
50 // it's up to the user to provide the definition of these:
53 T user_domain_error(const char* function, const char* message, const T& val);
55 T user_pole_error(const char* function, const char* message, const T& val);
57 T user_overflow_error(const char* function, const char* message, const T& val);
59 T user_underflow_error(const char* function, const char* message, const T& val);
61 T user_denorm_error(const char* function, const char* message, const T& val);
63 T user_evaluation_error(const char* function, const char* message, const T& val);
64 template <class T, class TargetType>
65 T user_rounding_error(const char* function, const char* message, const T& val, const TargetType& t);
67 T user_indeterminate_result_error(const char* function, const char* message, const T& val);
72 // Helper function to avoid binding rvalue to non-const-reference,
73 // in other words a warning suppression mechanism:
75 template <class Formatter, class Group>
76 inline std::string do_format(Formatter f, const Group& g)
81 template <class E, class T>
82 void raise_error(const char* function, const char* message)
85 function = "Unknown function operating on type %1%";
87 message = "Cause unknown";
89 std::string msg("Error in function ");
90 msg += (boost::format(function) % typeid(T).name()).str();
95 boost::throw_exception(e);
98 template <class E, class T>
99 void raise_error(const char* function, const char* message, const T& val)
102 function = "Unknown function operating on type %1%";
104 message = "Cause unknown: error caused by bad argument with value %1%";
106 std::string msg("Error in function ");
107 msg += (boost::format(function) % typeid(T).name()).str();
111 int prec = 2 + (boost::math::policies::digits<T, boost::math::policies::policy<> >() * 30103UL) / 100000UL;
112 msg = do_format(boost::format(msg), boost::io::group(std::setprecision(prec), val));
115 boost::throw_exception(e);
119 inline T raise_domain_error(
120 const char* function,
123 const ::boost::math::policies::domain_error< ::boost::math::policies::throw_on_error>&)
125 raise_error<std::domain_error, T>(function, message, val);
126 // we never get here:
127 return std::numeric_limits<T>::quiet_NaN();
131 inline T raise_domain_error(
135 const ::boost::math::policies::domain_error< ::boost::math::policies::ignore_error>&)
137 // This may or may not do the right thing, but the user asked for the error
138 // to be ignored so here we go anyway:
139 return std::numeric_limits<T>::quiet_NaN();
143 inline T raise_domain_error(
147 const ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>&)
150 // This may or may not do the right thing, but the user asked for the error
151 // to be silent so here we go anyway:
152 return std::numeric_limits<T>::quiet_NaN();
156 inline T raise_domain_error(
157 const char* function,
160 const ::boost::math::policies::domain_error< ::boost::math::policies::user_error>&)
162 return user_domain_error(function, message, val);
166 inline T raise_pole_error(
167 const char* function,
170 const ::boost::math::policies::pole_error< ::boost::math::policies::throw_on_error>&)
172 return boost::math::policies::detail::raise_domain_error(function, message, val, ::boost::math::policies::domain_error< ::boost::math::policies::throw_on_error>());
176 inline T raise_pole_error(
177 const char* function,
180 const ::boost::math::policies::pole_error< ::boost::math::policies::ignore_error>&)
182 return ::boost::math::policies::detail::raise_domain_error(function, message, val, ::boost::math::policies::domain_error< ::boost::math::policies::ignore_error>());
186 inline T raise_pole_error(
187 const char* function,
190 const ::boost::math::policies::pole_error< ::boost::math::policies::errno_on_error>&)
192 return ::boost::math::policies::detail::raise_domain_error(function, message, val, ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>());
196 inline T raise_pole_error(
197 const char* function,
200 const ::boost::math::policies::pole_error< ::boost::math::policies::user_error>&)
202 return user_pole_error(function, message, val);
207 inline T raise_overflow_error(
208 const char* function,
210 const ::boost::math::policies::overflow_error< ::boost::math::policies::throw_on_error>&)
212 raise_error<std::overflow_error, T>(function, message ? message : "numeric overflow");
213 // We should never get here:
214 return std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : boost::math::tools::max_value<T>();
218 inline T raise_overflow_error(
219 const char* function,
222 const ::boost::math::policies::overflow_error< ::boost::math::policies::throw_on_error>&)
224 raise_error<std::overflow_error, T>(function, message ? message : "numeric overflow", val);
225 // We should never get here:
226 return std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : boost::math::tools::max_value<T>();
230 inline T raise_overflow_error(
233 const ::boost::math::policies::overflow_error< ::boost::math::policies::ignore_error>&)
235 // This may or may not do the right thing, but the user asked for the error
236 // to be ignored so here we go anyway:
237 return std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : boost::math::tools::max_value<T>();
241 inline T raise_overflow_error(
244 const ::boost::math::policies::overflow_error< ::boost::math::policies::errno_on_error>&)
247 // This may or may not do the right thing, but the user asked for the error
248 // to be silent so here we go anyway:
249 return std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : boost::math::tools::max_value<T>();
253 inline T raise_overflow_error(
254 const char* function,
256 const ::boost::math::policies::overflow_error< ::boost::math::policies::user_error>&)
258 return user_overflow_error(function, message, std::numeric_limits<T>::infinity());
263 inline T raise_underflow_error(
264 const char* function,
266 const ::boost::math::policies::underflow_error< ::boost::math::policies::throw_on_error>&)
268 raise_error<std::underflow_error, T>(function, message ? message : "numeric underflow");
269 // We should never get here:
274 inline T raise_underflow_error(
277 const ::boost::math::policies::underflow_error< ::boost::math::policies::ignore_error>&)
279 // This may or may not do the right thing, but the user asked for the error
280 // to be ignored so here we go anyway:
285 inline T raise_underflow_error(
286 const char* /* function */,
287 const char* /* message */,
288 const ::boost::math::policies::underflow_error< ::boost::math::policies::errno_on_error>&)
291 // This may or may not do the right thing, but the user asked for the error
292 // to be silent so here we go anyway:
297 inline T raise_underflow_error(
298 const char* function,
300 const ::boost::math::policies::underflow_error< ::boost::math::policies::user_error>&)
302 return user_underflow_error(function, message, T(0));
306 inline T raise_denorm_error(
307 const char* function,
310 const ::boost::math::policies::denorm_error< ::boost::math::policies::throw_on_error>&)
312 raise_error<std::underflow_error, T>(function, message ? message : "denormalised result");
313 // we never get here:
318 inline T raise_denorm_error(
322 const ::boost::math::policies::denorm_error< ::boost::math::policies::ignore_error>&)
324 // This may or may not do the right thing, but the user asked for the error
325 // to be ignored so here we go anyway:
330 inline T raise_denorm_error(
334 const ::boost::math::policies::denorm_error< ::boost::math::policies::errno_on_error>&)
337 // This may or may not do the right thing, but the user asked for the error
338 // to be silent so here we go anyway:
343 inline T raise_denorm_error(
344 const char* function,
347 const ::boost::math::policies::denorm_error< ::boost::math::policies::user_error>&)
349 return user_denorm_error(function, message, val);
353 inline T raise_evaluation_error(
354 const char* function,
357 const ::boost::math::policies::evaluation_error< ::boost::math::policies::throw_on_error>&)
359 raise_error<boost::math::evaluation_error, T>(function, message, val);
360 // we never get here:
365 inline T raise_evaluation_error(
369 const ::boost::math::policies::evaluation_error< ::boost::math::policies::ignore_error>&)
371 // This may or may not do the right thing, but the user asked for the error
372 // to be ignored so here we go anyway:
377 inline T raise_evaluation_error(
381 const ::boost::math::policies::evaluation_error< ::boost::math::policies::errno_on_error>&)
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:
390 inline T raise_evaluation_error(
391 const char* function,
394 const ::boost::math::policies::evaluation_error< ::boost::math::policies::user_error>&)
396 return user_evaluation_error(function, message, val);
399 template <class T, class TargetType>
400 inline TargetType raise_rounding_error(
401 const char* function,
405 const ::boost::math::policies::rounding_error< ::boost::math::policies::throw_on_error>&)
407 raise_error<boost::math::rounding_error, T>(function, message, val);
408 // we never get here:
409 return TargetType(0);
412 template <class T, class TargetType>
413 inline TargetType raise_rounding_error(
418 const ::boost::math::policies::rounding_error< ::boost::math::policies::ignore_error>&)
420 // This may or may not do the right thing, but the user asked for the error
421 // to be ignored so here we go anyway:
422 BOOST_STATIC_ASSERT(std::numeric_limits<TargetType>::is_specialized);
423 return val > 0 ? (std::numeric_limits<TargetType>::max)() : (std::numeric_limits<TargetType>::is_integer ? (std::numeric_limits<TargetType>::min)() : -(std::numeric_limits<TargetType>::max)());
426 template <class T, class TargetType>
427 inline TargetType raise_rounding_error(
432 const ::boost::math::policies::rounding_error< ::boost::math::policies::errno_on_error>&)
435 // This may or may not do the right thing, but the user asked for the error
436 // to be silent so here we go anyway:
437 BOOST_STATIC_ASSERT(std::numeric_limits<TargetType>::is_specialized);
438 return val > 0 ? (std::numeric_limits<TargetType>::max)() : (std::numeric_limits<TargetType>::is_integer ? (std::numeric_limits<TargetType>::min)() : -(std::numeric_limits<TargetType>::max)());
441 template <class T, class TargetType>
442 inline TargetType raise_rounding_error(
443 const char* function,
447 const ::boost::math::policies::rounding_error< ::boost::math::policies::user_error>&)
449 return user_rounding_error(function, message, val, t);
452 template <class T, class R>
453 inline T raise_indeterminate_result_error(
454 const char* function,
458 const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::throw_on_error>&)
460 raise_error<std::domain_error, T>(function, message, val);
461 // we never get here:
462 return std::numeric_limits<T>::quiet_NaN();
465 template <class T, class R>
466 inline T raise_indeterminate_result_error(
471 const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::ignore_error>&)
473 // This may or may not do the right thing, but the user asked for the error
474 // to be ignored so here we go anyway:
478 template <class T, class R>
479 inline T raise_indeterminate_result_error(
484 const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::errno_on_error>&)
487 // This may or may not do the right thing, but the user asked for the error
488 // to be silent so here we go anyway:
492 template <class T, class R>
493 inline T raise_indeterminate_result_error(
494 const char* function,
498 const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::user_error>&)
500 return user_indeterminate_result_error(function, message, val);
503 } // namespace detail
505 template <class T, class Policy>
506 inline T raise_domain_error(const char* function, const char* message, const T& val, const Policy&)
508 typedef typename Policy::domain_error_type policy_type;
509 return detail::raise_domain_error(
510 function, message ? message : "Domain Error evaluating function at %1%",
514 template <class T, class Policy>
515 inline T raise_pole_error(const char* function, const char* message, const T& val, const Policy&)
517 typedef typename Policy::pole_error_type policy_type;
518 return detail::raise_pole_error(
519 function, message ? message : "Evaluation of function at pole %1%",
523 template <class T, class Policy>
524 inline T raise_overflow_error(const char* function, const char* message, const Policy&)
526 typedef typename Policy::overflow_error_type policy_type;
527 return detail::raise_overflow_error<T>(
528 function, message ? message : "Overflow Error",
532 template <class T, class Policy>
533 inline T raise_overflow_error(const char* function, const char* message, const T& val, const Policy&)
535 typedef typename Policy::overflow_error_type policy_type;
536 return detail::raise_overflow_error(
537 function, message ? message : "Overflow evaluating function at %1%",
541 template <class T, class Policy>
542 inline T raise_underflow_error(const char* function, const char* message, const Policy&)
544 typedef typename Policy::underflow_error_type policy_type;
545 return detail::raise_underflow_error<T>(
546 function, message ? message : "Underflow Error",
550 template <class T, class Policy>
551 inline T raise_denorm_error(const char* function, const char* message, const T& val, const Policy&)
553 typedef typename Policy::denorm_error_type policy_type;
554 return detail::raise_denorm_error<T>(
555 function, message ? message : "Denorm Error",
560 template <class T, class Policy>
561 inline T raise_evaluation_error(const char* function, const char* message, const T& val, const Policy&)
563 typedef typename Policy::evaluation_error_type policy_type;
564 return detail::raise_evaluation_error(
565 function, message ? message : "Internal Evaluation Error, best value so far was %1%",
569 template <class T, class TargetType, class Policy>
570 inline TargetType raise_rounding_error(const char* function, const char* message, const T& val, const TargetType& t, const Policy&)
572 typedef typename Policy::rounding_error_type policy_type;
573 return detail::raise_rounding_error(
574 function, message ? message : "Value %1% can not be represented in the target integer type.",
575 val, t, policy_type());
578 template <class T, class R, class Policy>
579 inline T raise_indeterminate_result_error(const char* function, const char* message, const T& val, const R& result, const Policy&)
581 typedef typename Policy::indeterminate_result_error_type policy_type;
582 return detail::raise_indeterminate_result_error(
583 function, message ? message : "Indeterminate result with value %1%",
584 val, result, policy_type());
588 // checked_narrowing_cast:
593 template <class R, class T, class Policy>
594 inline bool check_overflow(T val, R* result, const char* function, const Policy& pol)
597 if(fabs(val) > tools::max_value<R>())
599 *result = static_cast<R>(boost::math::policies::detail::raise_overflow_error<R>(function, 0, pol));
604 template <class R, class T, class Policy>
605 inline bool check_overflow(std::complex<T> val, R* result, const char* function, const Policy& pol)
607 typedef typename R::value_type r_type;
609 bool r = check_overflow<r_type>(val.real(), &re, function, pol);
610 r = check_overflow<r_type>(val.imag(), &im, function, pol) || r;
614 template <class R, class T, class Policy>
615 inline bool check_underflow(T val, R* result, const char* function, const Policy& pol)
617 if((val != 0) && (static_cast<R>(val) == 0))
619 *result = static_cast<R>(boost::math::policies::detail::raise_underflow_error<R>(function, 0, pol));
624 template <class R, class T, class Policy>
625 inline bool check_underflow(std::complex<T> val, R* result, const char* function, const Policy& pol)
627 typedef typename R::value_type r_type;
629 bool r = check_underflow<r_type>(val.real(), &re, function, pol);
630 r = check_underflow<r_type>(val.imag(), &im, function, pol) || r;
634 template <class R, class T, class Policy>
635 inline bool check_denorm(T val, R* result, const char* function, const Policy& pol)
638 if((fabs(val) < static_cast<T>(tools::min_value<R>())) && (static_cast<R>(val) != 0))
640 *result = static_cast<R>(boost::math::policies::detail::raise_denorm_error<R>(function, 0, static_cast<R>(val), pol));
645 template <class R, class T, class Policy>
646 inline bool check_denorm(std::complex<T> val, R* result, const char* function, const Policy& pol)
648 typedef typename R::value_type r_type;
650 bool r = check_denorm<r_type>(val.real(), &re, function, pol);
651 r = check_denorm<r_type>(val.imag(), &im, function, pol) || r;
656 // Default instantiations with ignore_error policy.
657 template <class R, class T>
658 inline bool check_overflow(T /* val */, R* /* result */, const char* /* function */, const overflow_error<ignore_error>&){ return false; }
659 template <class R, class T>
660 inline bool check_overflow(std::complex<T> /* val */, R* /* result */, const char* /* function */, const overflow_error<ignore_error>&){ return false; }
661 template <class R, class T>
662 inline bool check_underflow(T /* val */, R* /* result */, const char* /* function */, const underflow_error<ignore_error>&){ return false; }
663 template <class R, class T>
664 inline bool check_underflow(std::complex<T> /* val */, R* /* result */, const char* /* function */, const underflow_error<ignore_error>&){ return false; }
665 template <class R, class T>
666 inline bool check_denorm(T /* val */, R* /* result*/, const char* /* function */, const denorm_error<ignore_error>&){ return false; }
667 template <class R, class T>
668 inline bool check_denorm(std::complex<T> /* val */, R* /* result*/, const char* /* function */, const denorm_error<ignore_error>&){ return false; }
670 } // namespace detail
672 template <class R, class Policy, class T>
673 inline R checked_narrowing_cast(T val, const char* function)
675 typedef typename Policy::overflow_error_type overflow_type;
676 typedef typename Policy::underflow_error_type underflow_type;
677 typedef typename Policy::denorm_error_type denorm_type;
679 // Most of what follows will evaluate to a no-op:
682 if(detail::check_overflow<R>(val, &result, function, overflow_type()))
684 if(detail::check_underflow<R>(val, &result, function, underflow_type()))
686 if(detail::check_denorm<R>(val, &result, function, denorm_type()))
689 return static_cast<R>(val);
692 template <class T, class Policy>
693 inline void check_series_iterations(const char* function, boost::uintmax_t max_iter, const Policy& pol)
695 if(max_iter >= policies::get_max_series_iterations<Policy>())
696 raise_evaluation_error<T>(
698 "Series evaluation exceeded %1% iterations, giving up now.", static_cast<T>(static_cast<double>(max_iter)), pol);
701 template <class T, class Policy>
702 inline void check_root_iterations(const char* function, boost::uintmax_t max_iter, const Policy& pol)
704 if(max_iter >= policies::get_max_root_iterations<Policy>())
705 raise_evaluation_error<T>(
707 "Root finding evaluation exceeded %1% iterations, giving up now.", static_cast<T>(static_cast<double>(max_iter)), pol);
710 } //namespace policies
713 # pragma warning(pop)
716 }} // namespaces boost/math
718 #endif // BOOST_MATH_POLICY_ERROR_HANDLING_HPP