/Src/Dependencies/Boost/boost/math/policies/error_handling.hpp

http://hadesmem.googlecode.com/ · C++ Header · 657 lines · 530 code · 69 blank · 58 comment · 21 complexity · 00a028b99f748990651685c6666e64c1 MD5 · raw file

  1. // Copyright John Maddock 2007.
  2. // Copyright Paul A. Bristow 2007.
  3. // Use, modification and distribution are subject to the
  4. // Boost Software License, Version 1.0. (See accompanying file
  5. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_MATH_POLICY_ERROR_HANDLING_HPP
  7. #define BOOST_MATH_POLICY_ERROR_HANDLING_HPP
  8. #include <stdexcept>
  9. #include <iomanip>
  10. #include <string>
  11. #include <cerrno>
  12. #include <boost/config/no_tr1/cmath.hpp>
  13. #include <stdexcept>
  14. #include <boost/math/tools/config.hpp>
  15. #include <boost/math/policies/policy.hpp>
  16. #include <boost/math/tools/precision.hpp>
  17. #include <boost/cstdint.hpp>
  18. #ifdef BOOST_MSVC
  19. # pragma warning(push) // Quiet warnings in boost/format.hpp
  20. # pragma warning(disable: 4996) // _SCL_SECURE_NO_DEPRECATE
  21. # pragma warning(disable: 4512) // assignment operator could not be generated.
  22. // And warnings in error handling:
  23. # pragma warning(disable: 4702) // unreachable code
  24. // Note that this only occurs when the compiler can deduce code is unreachable,
  25. // for example when policy macros are used to ignore errors rather than throw.
  26. #endif
  27. #include <boost/format.hpp>
  28. namespace boost{ namespace math{
  29. class evaluation_error : public std::runtime_error
  30. {
  31. public:
  32. evaluation_error(const std::string& s) : std::runtime_error(s){}
  33. };
  34. class rounding_error : public std::runtime_error
  35. {
  36. public:
  37. rounding_error(const std::string& s) : std::runtime_error(s){}
  38. };
  39. namespace policies{
  40. //
  41. // Forward declarations of user error handlers,
  42. // it's up to the user to provide the definition of these:
  43. //
  44. template <class T>
  45. T user_domain_error(const char* function, const char* message, const T& val);
  46. template <class T>
  47. T user_pole_error(const char* function, const char* message, const T& val);
  48. template <class T>
  49. T user_overflow_error(const char* function, const char* message, const T& val);
  50. template <class T>
  51. T user_underflow_error(const char* function, const char* message, const T& val);
  52. template <class T>
  53. T user_denorm_error(const char* function, const char* message, const T& val);
  54. template <class T>
  55. T user_evaluation_error(const char* function, const char* message, const T& val);
  56. template <class T, class TargetType>
  57. T user_rounding_error(const char* function, const char* message, const T& val, const TargetType& t);
  58. template <class T>
  59. T user_indeterminate_result_error(const char* function, const char* message, const T& val);
  60. namespace detail
  61. {
  62. //
  63. // Helper function to avoid binding rvalue to non-const-reference,
  64. // in other words a warning suppression mechansim:
  65. //
  66. template <class Formatter, class Group>
  67. inline std::string do_format(Formatter f, const Group& g)
  68. {
  69. return (f % g).str();
  70. }
  71. template <class E, class T>
  72. void raise_error(const char* function, const char* message)
  73. {
  74. if(function == 0)
  75. function = "Unknown function operating on type %1%";
  76. if(message == 0)
  77. message = "Cause unknown";
  78. std::string msg("Error in function ");
  79. msg += (boost::format(function) % typeid(T).name()).str();
  80. msg += ": ";
  81. msg += message;
  82. E e(msg);
  83. boost::throw_exception(e);
  84. }
  85. template <class E, class T>
  86. void raise_error(const char* function, const char* message, const T& val)
  87. {
  88. if(function == 0)
  89. function = "Unknown function operating on type %1%";
  90. if(message == 0)
  91. message = "Cause unknown: error caused by bad argument with value %1%";
  92. std::string msg("Error in function ");
  93. msg += (boost::format(function) % typeid(T).name()).str();
  94. msg += ": ";
  95. msg += message;
  96. int prec = 2 + (boost::math::policies::digits<T, boost::math::policies::policy<> >() * 30103UL) / 100000UL;
  97. msg = do_format(boost::format(msg), boost::io::group(std::setprecision(prec), val));
  98. E e(msg);
  99. boost::throw_exception(e);
  100. }
  101. template <class T>
  102. inline T raise_domain_error(
  103. const char* function,
  104. const char* message,
  105. const T& val,
  106. const ::boost::math::policies::domain_error< ::boost::math::policies::throw_on_error>&)
  107. {
  108. raise_error<std::domain_error, T>(function, message, val);
  109. // we never get here:
  110. return std::numeric_limits<T>::quiet_NaN();
  111. }
  112. template <class T>
  113. inline T raise_domain_error(
  114. const char* ,
  115. const char* ,
  116. const T& ,
  117. const ::boost::math::policies::domain_error< ::boost::math::policies::ignore_error>&)
  118. {
  119. // This may or may not do the right thing, but the user asked for the error
  120. // to be ignored so here we go anyway:
  121. return std::numeric_limits<T>::quiet_NaN();
  122. }
  123. template <class T>
  124. inline T raise_domain_error(
  125. const char* ,
  126. const char* ,
  127. const T& ,
  128. const ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>&)
  129. {
  130. errno = EDOM;
  131. // This may or may not do the right thing, but the user asked for the error
  132. // to be silent so here we go anyway:
  133. return std::numeric_limits<T>::quiet_NaN();
  134. }
  135. template <class T>
  136. inline T raise_domain_error(
  137. const char* function,
  138. const char* message,
  139. const T& val,
  140. const ::boost::math::policies::domain_error< ::boost::math::policies::user_error>&)
  141. {
  142. return user_domain_error(function, message, val);
  143. }
  144. template <class T>
  145. inline T raise_pole_error(
  146. const char* function,
  147. const char* message,
  148. const T& val,
  149. const ::boost::math::policies::pole_error< ::boost::math::policies::throw_on_error>&)
  150. {
  151. return boost::math::policies::detail::raise_domain_error(function, message, val, ::boost::math::policies::domain_error< ::boost::math::policies::throw_on_error>());
  152. }
  153. template <class T>
  154. inline T raise_pole_error(
  155. const char* function,
  156. const char* message,
  157. const T& val,
  158. const ::boost::math::policies::pole_error< ::boost::math::policies::ignore_error>&)
  159. {
  160. return ::boost::math::policies::detail::raise_domain_error(function, message, val, ::boost::math::policies::domain_error< ::boost::math::policies::ignore_error>());
  161. }
  162. template <class T>
  163. inline T raise_pole_error(
  164. const char* function,
  165. const char* message,
  166. const T& val,
  167. const ::boost::math::policies::pole_error< ::boost::math::policies::errno_on_error>&)
  168. {
  169. return ::boost::math::policies::detail::raise_domain_error(function, message, val, ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>());
  170. }
  171. template <class T>
  172. inline T raise_pole_error(
  173. const char* function,
  174. const char* message,
  175. const T& val,
  176. const ::boost::math::policies::pole_error< ::boost::math::policies::user_error>&)
  177. {
  178. return user_pole_error(function, message, val);
  179. }
  180. template <class T>
  181. inline T raise_overflow_error(
  182. const char* function,
  183. const char* message,
  184. const ::boost::math::policies::overflow_error< ::boost::math::policies::throw_on_error>&)
  185. {
  186. raise_error<std::overflow_error, T>(function, message ? message : "numeric overflow");
  187. // we never get here:
  188. return std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : boost::math::tools::max_value<T>();
  189. }
  190. template <class T>
  191. inline T raise_overflow_error(
  192. const char* ,
  193. const char* ,
  194. const ::boost::math::policies::overflow_error< ::boost::math::policies::ignore_error>&)
  195. {
  196. // This may or may not do the right thing, but the user asked for the error
  197. // to be ignored so here we go anyway:
  198. return std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : boost::math::tools::max_value<T>();
  199. }
  200. template <class T>
  201. inline T raise_overflow_error(
  202. const char* ,
  203. const char* ,
  204. const ::boost::math::policies::overflow_error< ::boost::math::policies::errno_on_error>&)
  205. {
  206. errno = ERANGE;
  207. // This may or may not do the right thing, but the user asked for the error
  208. // to be silent so here we go anyway:
  209. return std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : boost::math::tools::max_value<T>();
  210. }
  211. template <class T>
  212. inline T raise_overflow_error(
  213. const char* function,
  214. const char* message,
  215. const ::boost::math::policies::overflow_error< ::boost::math::policies::user_error>&)
  216. {
  217. return user_overflow_error(function, message, std::numeric_limits<T>::infinity());
  218. }
  219. template <class T>
  220. inline T raise_underflow_error(
  221. const char* function,
  222. const char* message,
  223. const ::boost::math::policies::underflow_error< ::boost::math::policies::throw_on_error>&)
  224. {
  225. raise_error<std::underflow_error, T>(function, message ? message : "numeric underflow");
  226. // we never get here:
  227. return 0;
  228. }
  229. template <class T>
  230. inline T raise_underflow_error(
  231. const char* ,
  232. const char* ,
  233. const ::boost::math::policies::underflow_error< ::boost::math::policies::ignore_error>&)
  234. {
  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 T(0);
  238. }
  239. template <class T>
  240. inline T raise_underflow_error(
  241. const char* /* function */,
  242. const char* /* message */,
  243. const ::boost::math::policies::underflow_error< ::boost::math::policies::errno_on_error>&)
  244. {
  245. errno = ERANGE;
  246. // This may or may not do the right thing, but the user asked for the error
  247. // to be silent so here we go anyway:
  248. return T(0);
  249. }
  250. template <class T>
  251. inline T raise_underflow_error(
  252. const char* function,
  253. const char* message,
  254. const ::boost::math::policies::underflow_error< ::boost::math::policies::user_error>&)
  255. {
  256. return user_underflow_error(function, message, T(0));
  257. }
  258. template <class T>
  259. inline T raise_denorm_error(
  260. const char* function,
  261. const char* message,
  262. const T& /* val */,
  263. const ::boost::math::policies::denorm_error< ::boost::math::policies::throw_on_error>&)
  264. {
  265. raise_error<std::underflow_error, T>(function, message ? message : "denormalised result");
  266. // we never get here:
  267. return T(0);
  268. }
  269. template <class T>
  270. inline T raise_denorm_error(
  271. const char* ,
  272. const char* ,
  273. const T& val,
  274. const ::boost::math::policies::denorm_error< ::boost::math::policies::ignore_error>&)
  275. {
  276. // This may or may not do the right thing, but the user asked for the error
  277. // to be ignored so here we go anyway:
  278. return val;
  279. }
  280. template <class T>
  281. inline T raise_denorm_error(
  282. const char* ,
  283. const char* ,
  284. const T& val,
  285. const ::boost::math::policies::denorm_error< ::boost::math::policies::errno_on_error>&)
  286. {
  287. errno = ERANGE;
  288. // This may or may not do the right thing, but the user asked for the error
  289. // to be silent so here we go anyway:
  290. return val;
  291. }
  292. template <class T>
  293. inline T raise_denorm_error(
  294. const char* function,
  295. const char* message,
  296. const T& val,
  297. const ::boost::math::policies::denorm_error< ::boost::math::policies::user_error>&)
  298. {
  299. return user_denorm_error(function, message, val);
  300. }
  301. template <class T>
  302. inline T raise_evaluation_error(
  303. const char* function,
  304. const char* message,
  305. const T& val,
  306. const ::boost::math::policies::evaluation_error< ::boost::math::policies::throw_on_error>&)
  307. {
  308. raise_error<boost::math::evaluation_error, T>(function, message, val);
  309. // we never get here:
  310. return T(0);
  311. }
  312. template <class T>
  313. inline T raise_evaluation_error(
  314. const char* ,
  315. const char* ,
  316. const T& val,
  317. const ::boost::math::policies::evaluation_error< ::boost::math::policies::ignore_error>&)
  318. {
  319. // This may or may not do the right thing, but the user asked for the error
  320. // to be ignored so here we go anyway:
  321. return val;
  322. }
  323. template <class T>
  324. inline T raise_evaluation_error(
  325. const char* ,
  326. const char* ,
  327. const T& val,
  328. const ::boost::math::policies::evaluation_error< ::boost::math::policies::errno_on_error>&)
  329. {
  330. errno = EDOM;
  331. // This may or may not do the right thing, but the user asked for the error
  332. // to be silent so here we go anyway:
  333. return val;
  334. }
  335. template <class T>
  336. inline T raise_evaluation_error(
  337. const char* function,
  338. const char* message,
  339. const T& val,
  340. const ::boost::math::policies::evaluation_error< ::boost::math::policies::user_error>&)
  341. {
  342. return user_evaluation_error(function, message, val);
  343. }
  344. template <class T, class TargetType>
  345. inline T raise_rounding_error(
  346. const char* function,
  347. const char* message,
  348. const T& val,
  349. const TargetType&,
  350. const ::boost::math::policies::rounding_error< ::boost::math::policies::throw_on_error>&)
  351. {
  352. raise_error<boost::math::rounding_error, T>(function, message, val);
  353. // we never get here:
  354. return T(0);
  355. }
  356. template <class T, class TargetType>
  357. inline T raise_rounding_error(
  358. const char* ,
  359. const char* ,
  360. const T& val,
  361. const TargetType&,
  362. const ::boost::math::policies::rounding_error< ::boost::math::policies::ignore_error>&)
  363. {
  364. // This may or may not do the right thing, but the user asked for the error
  365. // to be ignored so here we go anyway:
  366. return std::numeric_limits<T>::is_specialized ? (val > 0 ? (std::numeric_limits<T>::max)() : -(std::numeric_limits<T>::max)()): val;
  367. }
  368. template <class T, class TargetType>
  369. inline T raise_rounding_error(
  370. const char* ,
  371. const char* ,
  372. const T& val,
  373. const TargetType&,
  374. const ::boost::math::policies::rounding_error< ::boost::math::policies::errno_on_error>&)
  375. {
  376. errno = ERANGE;
  377. // This may or may not do the right thing, but the user asked for the error
  378. // to be silent so here we go anyway:
  379. return std::numeric_limits<T>::is_specialized ? (val > 0 ? (std::numeric_limits<T>::max)() : -(std::numeric_limits<T>::max)()): val;
  380. }
  381. template <class T, class TargetType>
  382. inline T raise_rounding_error(
  383. const char* function,
  384. const char* message,
  385. const T& val,
  386. const TargetType& t,
  387. const ::boost::math::policies::rounding_error< ::boost::math::policies::user_error>&)
  388. {
  389. return user_rounding_error(function, message, val, t);
  390. }
  391. template <class T, class R>
  392. inline T raise_indeterminate_result_error(
  393. const char* function,
  394. const char* message,
  395. const T& val,
  396. const R& ,
  397. const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::throw_on_error>&)
  398. {
  399. raise_error<std::domain_error, T>(function, message, val);
  400. // we never get here:
  401. return std::numeric_limits<T>::quiet_NaN();
  402. }
  403. template <class T, class R>
  404. inline T raise_indeterminate_result_error(
  405. const char* ,
  406. const char* ,
  407. const T& ,
  408. const R& result,
  409. const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::ignore_error>&)
  410. {
  411. // This may or may not do the right thing, but the user asked for the error
  412. // to be ignored so here we go anyway:
  413. return result;
  414. }
  415. template <class T, class R>
  416. inline T raise_indeterminate_result_error(
  417. const char* ,
  418. const char* ,
  419. const T& ,
  420. const R& result,
  421. const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::errno_on_error>&)
  422. {
  423. errno = EDOM;
  424. // This may or may not do the right thing, but the user asked for the error
  425. // to be silent so here we go anyway:
  426. return result;
  427. }
  428. template <class T, class R>
  429. inline T raise_indeterminate_result_error(
  430. const char* function,
  431. const char* message,
  432. const T& val,
  433. const R& ,
  434. const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::user_error>&)
  435. {
  436. return user_indeterminate_result_error(function, message, val);
  437. }
  438. } // namespace detail
  439. template <class T, class Policy>
  440. inline T raise_domain_error(const char* function, const char* message, const T& val, const Policy&)
  441. {
  442. typedef typename Policy::domain_error_type policy_type;
  443. return detail::raise_domain_error(
  444. function, message ? message : "Domain Error evaluating function at %1%",
  445. val, policy_type());
  446. }
  447. template <class T, class Policy>
  448. inline T raise_pole_error(const char* function, const char* message, const T& val, const Policy&)
  449. {
  450. typedef typename Policy::pole_error_type policy_type;
  451. return detail::raise_pole_error(
  452. function, message ? message : "Evaluation of function at pole %1%",
  453. val, policy_type());
  454. }
  455. template <class T, class Policy>
  456. inline T raise_overflow_error(const char* function, const char* message, const Policy&)
  457. {
  458. typedef typename Policy::overflow_error_type policy_type;
  459. return detail::raise_overflow_error<T>(
  460. function, message ? message : "Overflow Error",
  461. policy_type());
  462. }
  463. template <class T, class Policy>
  464. inline T raise_underflow_error(const char* function, const char* message, const Policy&)
  465. {
  466. typedef typename Policy::underflow_error_type policy_type;
  467. return detail::raise_underflow_error<T>(
  468. function, message ? message : "Underflow Error",
  469. policy_type());
  470. }
  471. template <class T, class Policy>
  472. inline T raise_denorm_error(const char* function, const char* message, const T& val, const Policy&)
  473. {
  474. typedef typename Policy::denorm_error_type policy_type;
  475. return detail::raise_denorm_error<T>(
  476. function, message ? message : "Denorm Error",
  477. val,
  478. policy_type());
  479. }
  480. template <class T, class Policy>
  481. inline T raise_evaluation_error(const char* function, const char* message, const T& val, const Policy&)
  482. {
  483. typedef typename Policy::evaluation_error_type policy_type;
  484. return detail::raise_evaluation_error(
  485. function, message ? message : "Internal Evaluation Error, best value so far was %1%",
  486. val, policy_type());
  487. }
  488. template <class T, class TargetType, class Policy>
  489. inline T raise_rounding_error(const char* function, const char* message, const T& val, const TargetType& t, const Policy&)
  490. {
  491. typedef typename Policy::rounding_error_type policy_type;
  492. return detail::raise_rounding_error(
  493. function, message ? message : "Value %1% can not be represented in the target integer type.",
  494. val, t, policy_type());
  495. }
  496. template <class T, class R, class Policy>
  497. inline T raise_indeterminate_result_error(const char* function, const char* message, const T& val, const R& result, const Policy&)
  498. {
  499. typedef typename Policy::indeterminate_result_error_type policy_type;
  500. return detail::raise_indeterminate_result_error(
  501. function, message ? message : "Indeterminate result with value %1%",
  502. val, result, policy_type());
  503. }
  504. //
  505. // checked_narrowing_cast:
  506. //
  507. namespace detail
  508. {
  509. template <class R, class T, class Policy>
  510. inline bool check_overflow(T val, R* result, const char* function, const Policy& pol)
  511. {
  512. BOOST_MATH_STD_USING
  513. if(fabs(val) > tools::max_value<R>())
  514. {
  515. *result = static_cast<R>(boost::math::policies::detail::raise_overflow_error<R>(function, 0, pol));
  516. return true;
  517. }
  518. return false;
  519. }
  520. template <class R, class T, class Policy>
  521. inline bool check_underflow(T val, R* result, const char* function, const Policy& pol)
  522. {
  523. if((val != 0) && (static_cast<R>(val) == 0))
  524. {
  525. *result = static_cast<R>(boost::math::policies::detail::raise_underflow_error<R>(function, 0, pol));
  526. return true;
  527. }
  528. return false;
  529. }
  530. template <class R, class T, class Policy>
  531. inline bool check_denorm(T val, R* result, const char* function, const Policy& pol)
  532. {
  533. BOOST_MATH_STD_USING
  534. if((fabs(val) < static_cast<T>(tools::min_value<R>())) && (static_cast<R>(val) != 0))
  535. {
  536. *result = static_cast<R>(boost::math::policies::detail::raise_denorm_error<R>(function, 0, static_cast<R>(val), pol));
  537. return true;
  538. }
  539. return false;
  540. }
  541. // Default instantiations with ignore_error policy.
  542. template <class R, class T>
  543. inline bool check_overflow(T /* val */, R* /* result */, const char* /* function */, const overflow_error<ignore_error>&){ return false; }
  544. template <class R, class T>
  545. inline bool check_underflow(T /* val */, R* /* result */, const char* /* function */, const underflow_error<ignore_error>&){ return false; }
  546. template <class R, class T>
  547. inline bool check_denorm(T /* val */, R* /* result*/, const char* /* function */, const denorm_error<ignore_error>&){ return false; }
  548. } // namespace detail
  549. template <class R, class Policy, class T>
  550. inline R checked_narrowing_cast(T val, const char* function)
  551. {
  552. typedef typename Policy::overflow_error_type overflow_type;
  553. typedef typename Policy::underflow_error_type underflow_type;
  554. typedef typename Policy::denorm_error_type denorm_type;
  555. //
  556. // Most of what follows will evaluate to a no-op:
  557. //
  558. R result = 0;
  559. if(detail::check_overflow<R>(val, &result, function, overflow_type()))
  560. return result;
  561. if(detail::check_underflow<R>(val, &result, function, underflow_type()))
  562. return result;
  563. if(detail::check_denorm<R>(val, &result, function, denorm_type()))
  564. return result;
  565. return static_cast<R>(val);
  566. }
  567. template <class Policy>
  568. inline void check_series_iterations(const char* function, boost::uintmax_t max_iter, const Policy& pol)
  569. {
  570. if(max_iter >= policies::get_max_series_iterations<Policy>())
  571. raise_evaluation_error<boost::uintmax_t>(
  572. function,
  573. "Series evaluation exceeded %1% iterations, giving up now.", max_iter, pol);
  574. }
  575. template <class Policy>
  576. inline void check_root_iterations(const char* function, boost::uintmax_t max_iter, const Policy& pol)
  577. {
  578. if(max_iter >= policies::get_max_root_iterations<Policy>())
  579. raise_evaluation_error<boost::uintmax_t>(
  580. function,
  581. "Root finding evaluation exceeded %1% iterations, giving up now.", max_iter, pol);
  582. }
  583. } //namespace policies
  584. #ifdef BOOST_MSVC
  585. # pragma warning(pop)
  586. #endif
  587. }} // namespaces boost/math
  588. #endif // BOOST_MATH_POLICY_ERROR_HANDLING_HPP