]> git.donarmstrong.com Git - rsem.git/blob - boost/math/policies/error_handling.hpp
6285e1e9f2b8c64d90d6f2df1d6b46de8b9ed241
[rsem.git] / boost / math / policies / error_handling.hpp
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 <cerrno>
15 #include <boost/config/no_tr1/cmath.hpp>
16 #include <stdexcept>
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>
21 #ifdef BOOST_MSVC
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.
29 #endif
30 #include <boost/format.hpp>
31
32 namespace boost{ namespace math{
33
34 class evaluation_error : public std::runtime_error
35 {
36 public:
37    evaluation_error(const std::string& s) : std::runtime_error(s){}
38 };
39
40 class rounding_error : public std::runtime_error
41 {
42 public:
43    rounding_error(const std::string& s) : std::runtime_error(s){}
44 };
45
46 namespace policies{
47 //
48 // Forward declarations of user error handlers, 
49 // it's up to the user to provide the definition of these:
50 //
51 template <class T>
52 T user_domain_error(const char* function, const char* message, const T& val);
53 template <class T>
54 T user_pole_error(const char* function, const char* message, const T& val);
55 template <class T>
56 T user_overflow_error(const char* function, const char* message, const T& val);
57 template <class T>
58 T user_underflow_error(const char* function, const char* message, const T& val);
59 template <class T>
60 T user_denorm_error(const char* function, const char* message, const T& val);
61 template <class T>
62 T user_evaluation_error(const char* function, const char* message, const T& val);
63 template <class T>
64 T user_rounding_error(const char* function, const char* message, const T& val);
65 template <class T>
66 T user_indeterminate_result_error(const char* function, const char* message, const T& val);
67
68 namespace detail
69 {
70 //
71 // Helper function to avoid binding rvalue to non-const-reference,
72 // in other words a warning suppression mechansim:
73 //
74 template <class Formatter, class Group>
75 inline std::string do_format(Formatter f, const Group& g)
76 {
77    return (f % g).str();
78 }
79
80 template <class E, class T>
81 void raise_error(const char* function, const char* message)
82 {
83   if(function == 0)
84        function = "Unknown function operating on type %1%";
85   if(message == 0)
86        message = "Cause unknown";
87
88   std::string msg("Error in function ");
89   msg += (boost::format(function) % typeid(T).name()).str();
90   msg += ": ";
91   msg += message;
92
93   E e(msg);
94   boost::throw_exception(e);
95 }
96
97 template <class E, class T>
98 void raise_error(const char* function, const char* message, const T& val)
99 {
100   if(function == 0)
101      function = "Unknown function operating on type %1%";
102   if(message == 0)
103      message = "Cause unknown: error caused by bad argument with value %1%";
104
105   std::string msg("Error in function ");
106   msg += (boost::format(function) % typeid(T).name()).str();
107   msg += ": ";
108   msg += message;
109
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));
112
113   E e(msg);
114   boost::throw_exception(e);
115 }
116
117 template <class T>
118 inline T raise_domain_error(
119            const char* function, 
120            const char* message, 
121            const T& val, 
122            const ::boost::math::policies::domain_error< ::boost::math::policies::throw_on_error>&)
123 {
124    raise_error<std::domain_error, T>(function, message, val);
125    // we never get here:
126    return std::numeric_limits<T>::quiet_NaN();
127 }
128
129 template <class T>
130 inline T raise_domain_error(
131            const char* , 
132            const char* , 
133            const T& , 
134            const ::boost::math::policies::domain_error< ::boost::math::policies::ignore_error>&)
135 {
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();
139 }
140
141 template <class T>
142 inline T raise_domain_error(
143            const char* , 
144            const char* , 
145            const T& , 
146            const ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>&)
147 {
148    errno = EDOM;
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();
152 }
153
154 template <class T>
155 inline T raise_domain_error(
156            const char* function, 
157            const char* message, 
158            const T& val, 
159            const  ::boost::math::policies::domain_error< ::boost::math::policies::user_error>&)
160 {
161    return user_domain_error(function, message, val);
162 }
163
164 template <class T>
165 inline T raise_pole_error(
166            const char* function, 
167            const char* message, 
168            const T& val, 
169            const  ::boost::math::policies::pole_error< ::boost::math::policies::throw_on_error>&)
170 {
171    return boost::math::policies::detail::raise_domain_error(function, message, val,  ::boost::math::policies::domain_error< ::boost::math::policies::throw_on_error>());
172 }
173
174 template <class T>
175 inline T raise_pole_error(
176            const char* function, 
177            const char* message, 
178            const T& val, 
179            const  ::boost::math::policies::pole_error< ::boost::math::policies::ignore_error>&)
180 {
181    return  ::boost::math::policies::detail::raise_domain_error(function, message, val,  ::boost::math::policies::domain_error< ::boost::math::policies::ignore_error>());
182 }
183
184 template <class T>
185 inline T raise_pole_error(
186            const char* function, 
187            const char* message, 
188            const T& val, 
189            const  ::boost::math::policies::pole_error< ::boost::math::policies::errno_on_error>&)
190 {
191    return  ::boost::math::policies::detail::raise_domain_error(function, message, val,  ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>());
192 }
193
194 template <class T>
195 inline T raise_pole_error(
196            const char* function, 
197            const char* message, 
198            const T& val, 
199            const  ::boost::math::policies::pole_error< ::boost::math::policies::user_error>&)
200 {
201    return user_pole_error(function, message, val);
202 }
203
204 template <class T>
205 inline T raise_overflow_error(
206            const char* function, 
207            const char* message, 
208            const  ::boost::math::policies::overflow_error< ::boost::math::policies::throw_on_error>&)
209 {
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>();
213 }
214
215 template <class T>
216 inline T raise_overflow_error(
217            const char* , 
218            const char* , 
219            const  ::boost::math::policies::overflow_error< ::boost::math::policies::ignore_error>&)
220 {
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>();
224 }
225
226 template <class T>
227 inline T raise_overflow_error(
228            const char* , 
229            const char* , 
230            const  ::boost::math::policies::overflow_error< ::boost::math::policies::errno_on_error>&)
231 {
232    errno = ERANGE;
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>();
236 }
237
238 template <class T>
239 inline T raise_overflow_error(
240            const char* function, 
241            const char* message, 
242            const  ::boost::math::policies::overflow_error< ::boost::math::policies::user_error>&)
243 {
244    return user_overflow_error(function, message, std::numeric_limits<T>::infinity());
245 }
246
247 template <class T>
248 inline T raise_underflow_error(
249            const char* function, 
250            const char* message, 
251            const  ::boost::math::policies::underflow_error< ::boost::math::policies::throw_on_error>&)
252 {
253    raise_error<std::underflow_error, T>(function, message ? message : "numeric underflow");
254    // we never get here:
255    return 0;
256 }
257
258 template <class T>
259 inline T raise_underflow_error(
260            const char* , 
261            const char* , 
262            const  ::boost::math::policies::underflow_error< ::boost::math::policies::ignore_error>&)
263 {
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:
266    return T(0);
267 }
268
269 template <class T>
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>&)
274 {
275    errno = ERANGE;
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:
278    return T(0);
279 }
280
281 template <class T>
282 inline T raise_underflow_error(
283            const char* function, 
284            const char* message, 
285            const  ::boost::math::policies::underflow_error< ::boost::math::policies::user_error>&)
286 {
287    return user_underflow_error(function, message, T(0));
288 }
289
290 template <class T>
291 inline T raise_denorm_error(
292            const char* function, 
293            const char* message, 
294            const T& /* val */,
295            const  ::boost::math::policies::denorm_error< ::boost::math::policies::throw_on_error>&)
296 {
297    raise_error<std::underflow_error, T>(function, message ? message : "denormalised result");
298    // we never get here:
299    return T(0);
300 }
301
302 template <class T>
303 inline T raise_denorm_error(
304            const char* , 
305            const char* , 
306            const T&  val,
307            const  ::boost::math::policies::denorm_error< ::boost::math::policies::ignore_error>&)
308 {
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:
311    return val;
312 }
313
314 template <class T>
315 inline T raise_denorm_error(
316            const char* , 
317            const char* , 
318            const T& val,
319            const  ::boost::math::policies::denorm_error< ::boost::math::policies::errno_on_error>&)
320 {
321    errno = ERANGE;
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:
324    return val;
325 }
326
327 template <class T>
328 inline T raise_denorm_error(
329            const char* function, 
330            const char* message, 
331            const T& val,
332            const  ::boost::math::policies::denorm_error< ::boost::math::policies::user_error>&)
333 {
334    return user_denorm_error(function, message, val);
335 }
336
337 template <class T>
338 inline T raise_evaluation_error(
339            const char* function, 
340            const char* message, 
341            const T& val, 
342            const  ::boost::math::policies::evaluation_error< ::boost::math::policies::throw_on_error>&)
343 {
344    raise_error<boost::math::evaluation_error, T>(function, message, val);
345    // we never get here:
346    return T(0);
347 }
348
349 template <class T>
350 inline T raise_evaluation_error(
351            const char* , 
352            const char* , 
353            const T& val, 
354            const  ::boost::math::policies::evaluation_error< ::boost::math::policies::ignore_error>&)
355 {
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:
358    return val;
359 }
360
361 template <class T>
362 inline T raise_evaluation_error(
363            const char* , 
364            const char* , 
365            const T& val, 
366            const  ::boost::math::policies::evaluation_error< ::boost::math::policies::errno_on_error>&)
367 {
368    errno = EDOM;
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:
371    return val;
372 }
373
374 template <class T>
375 inline T raise_evaluation_error(
376            const char* function, 
377            const char* message, 
378            const T& val, 
379            const  ::boost::math::policies::evaluation_error< ::boost::math::policies::user_error>&)
380 {
381    return user_evaluation_error(function, message, val);
382 }
383
384 template <class T>
385 inline T raise_rounding_error(
386            const char* function, 
387            const char* message, 
388            const T& val, 
389            const  ::boost::math::policies::rounding_error< ::boost::math::policies::throw_on_error>&)
390 {
391    raise_error<boost::math::rounding_error, T>(function, message, val);
392    // we never get here:
393    return T(0);
394 }
395
396 template <class T>
397 inline T raise_rounding_error(
398            const char* , 
399            const char* , 
400            const T& val, 
401            const  ::boost::math::policies::rounding_error< ::boost::math::policies::ignore_error>&)
402 {
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:
405    return val;
406 }
407
408 template <class T>
409 inline T raise_rounding_error(
410            const char* , 
411            const char* , 
412            const T& val, 
413            const  ::boost::math::policies::rounding_error< ::boost::math::policies::errno_on_error>&)
414 {
415    errno = ERANGE;
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:
418    return val;
419 }
420
421 template <class T>
422 inline T raise_rounding_error(
423            const char* function, 
424            const char* message, 
425            const T& val, 
426            const  ::boost::math::policies::rounding_error< ::boost::math::policies::user_error>&)
427 {
428    return user_rounding_error(function, message, val);
429 }
430
431 template <class T, class R>
432 inline T raise_indeterminate_result_error(
433            const char* function, 
434            const char* message, 
435            const T& val, 
436            const R& ,
437            const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::throw_on_error>&)
438 {
439    raise_error<std::domain_error, T>(function, message, val);
440    // we never get here:
441    return std::numeric_limits<T>::quiet_NaN();
442 }
443
444 template <class T, class R>
445 inline T raise_indeterminate_result_error(
446            const char* , 
447            const char* , 
448            const T& , 
449            const R& result, 
450            const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::ignore_error>&)
451 {
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:
454    return result;
455 }
456
457 template <class T, class R>
458 inline T raise_indeterminate_result_error(
459            const char* , 
460            const char* , 
461            const T& , 
462            const R& result, 
463            const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::errno_on_error>&)
464 {
465    errno = EDOM;
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:
468    return result;
469 }
470
471 template <class T, class R>
472 inline T raise_indeterminate_result_error(
473            const char* function, 
474            const char* message, 
475            const T& val, 
476            const R& , 
477            const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::user_error>&)
478 {
479    return user_indeterminate_result_error(function, message, val);
480 }
481
482 }  // namespace detail
483
484 template <class T, class Policy>
485 inline T raise_domain_error(const char* function, const char* message, const T& val, const Policy&)
486 {
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%", 
490       val, policy_type());
491 }
492
493 template <class T, class Policy>
494 inline T raise_pole_error(const char* function, const char* message, const T& val, const Policy&)
495 {
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%", 
499       val, policy_type());
500 }
501
502 template <class T, class Policy>
503 inline T raise_overflow_error(const char* function, const char* message, const Policy&)
504 {
505    typedef typename Policy::overflow_error_type policy_type;
506    return detail::raise_overflow_error<T>(
507       function, message ? message : "Overflow Error", 
508       policy_type());
509 }
510
511 template <class T, class Policy>
512 inline T raise_underflow_error(const char* function, const char* message, const Policy&)
513 {
514    typedef typename Policy::underflow_error_type policy_type;
515    return detail::raise_underflow_error<T>(
516       function, message ? message : "Underflow Error", 
517       policy_type());
518 }
519
520 template <class T, class Policy>
521 inline T raise_denorm_error(const char* function, const char* message, const T& val, const Policy&)
522 {
523    typedef typename Policy::denorm_error_type policy_type;
524    return detail::raise_denorm_error<T>(
525       function, message ? message : "Denorm Error", 
526       val,
527       policy_type());
528 }
529
530 template <class T, class Policy>
531 inline T raise_evaluation_error(const char* function, const char* message, const T& val, const Policy&)
532 {
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%", 
536       val, policy_type());
537 }
538
539 template <class T, class Policy>
540 inline T raise_rounding_error(const char* function, const char* message, const T& val, const Policy&)
541 {
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.", 
545       val, policy_type());
546 }
547
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&)
550 {
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());
555 }
556
557 //
558 // checked_narrowing_cast:
559 //
560 namespace detail
561 {
562
563 template <class R, class T, class Policy>
564 inline bool check_overflow(T val, R* result, const char* function, const Policy& pol)
565 {
566    BOOST_MATH_STD_USING
567    if(fabs(val) > tools::max_value<R>())
568    {
569       *result = static_cast<R>(boost::math::policies::detail::raise_overflow_error<R>(function, 0, pol));
570       return true;
571    }
572    return false;
573 }
574 template <class R, class T, class Policy>
575 inline bool check_underflow(T val, R* result, const char* function, const Policy& pol)
576 {
577    if((val != 0) && (static_cast<R>(val) == 0))
578    {
579       *result = static_cast<R>(boost::math::policies::detail::raise_underflow_error<R>(function, 0, pol));
580       return true;
581    }
582    return false;
583 }
584 template <class R, class T, class Policy>
585 inline bool check_denorm(T val, R* result, const char* function, const Policy& pol)
586 {
587    BOOST_MATH_STD_USING
588    if((fabs(val) < static_cast<T>(tools::min_value<R>())) && (static_cast<R>(val) != 0))
589    {
590       *result = static_cast<R>(boost::math::policies::detail::raise_denorm_error<R>(function, 0, static_cast<R>(val), pol));
591       return true;
592    }
593    return false;
594 }
595
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; }
603
604 } // namespace detail
605
606 template <class R, class Policy, class T>
607 inline R checked_narrowing_cast(T val, const char* function)
608 {
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;
612    //
613    // Most of what follows will evaluate to a no-op:
614    //
615    R result;
616    if(detail::check_overflow<R>(val, &result, function, overflow_type()))
617       return result;
618    if(detail::check_underflow<R>(val, &result, function, underflow_type()))
619       return result;
620    if(detail::check_denorm<R>(val, &result, function, denorm_type()))
621       return result;
622
623    return static_cast<R>(val);
624 }
625
626 template <class Policy>
627 inline void check_series_iterations(const char* function, boost::uintmax_t max_iter, const Policy& pol)
628 {
629    if(max_iter >= policies::get_max_series_iterations<Policy>())
630       raise_evaluation_error<boost::uintmax_t>(
631          function,
632          "Series evaluation exceeded %1% iterations, giving up now.", max_iter, pol);
633 }
634
635 template <class Policy>
636 inline void check_root_iterations(const char* function, boost::uintmax_t max_iter, const Policy& pol)
637 {
638    if(max_iter >= policies::get_max_root_iterations<Policy>())
639       raise_evaluation_error<boost::uintmax_t>(
640          function,
641          "Root finding evaluation exceeded %1% iterations, giving up now.", max_iter, pol);
642 }
643
644 } //namespace policies
645
646 #ifdef BOOST_MSVC
647 #  pragma warning(pop)
648 #endif
649
650 }} // namespaces boost/math
651
652 #endif // BOOST_MATH_POLICY_ERROR_HANDLING_HPP
653