converter_policies.hpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // (c) Copyright Fernando Luis Cacciola Carballal 2000-2004
  2. // Use, modification, and distribution is subject to the Boost Software
  3. // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. // See library home page at http://www.boost.org/libs/numeric/conversion
  6. //
  7. // Contact the author at: fernando_cacciola@hotmail.com
  8. //
  9. #ifndef BOOST_NUMERIC_CONVERSION_CONVERTER_POLICIES_FLC_12NOV2002_HPP
  10. #define BOOST_NUMERIC_CONVERSION_CONVERTER_POLICIES_FLC_12NOV2002_HPP
  11. #include <typeinfo> // for std::bad_cast
  12. #include <boost/config/no_tr1/cmath.hpp> // for std::floor and std::ceil
  13. #include <boost/throw_exception.hpp>
  14. #include <functional>
  15. #include "boost/type_traits/is_arithmetic.hpp"
  16. #include "boost/mpl/if.hpp"
  17. #include "boost/mpl/integral_c.hpp"
  18. namespace boost { namespace numeric
  19. {
  20. template<class S>
  21. struct Trunc
  22. {
  23. typedef S source_type ;
  24. typedef typename mpl::if_< is_arithmetic<S>,S,S const&>::type argument_type ;
  25. static source_type nearbyint ( argument_type s )
  26. {
  27. #if !defined(BOOST_NO_STDC_NAMESPACE)
  28. using std::floor ;
  29. using std::ceil ;
  30. #endif
  31. return s < static_cast<S>(0) ? ceil(s) : floor(s) ;
  32. }
  33. typedef mpl::integral_c< std::float_round_style, std::round_toward_zero> round_style ;
  34. } ;
  35. template<class S>
  36. struct Floor
  37. {
  38. typedef S source_type ;
  39. typedef typename mpl::if_< is_arithmetic<S>,S,S const&>::type argument_type ;
  40. static source_type nearbyint ( argument_type s )
  41. {
  42. #if !defined(BOOST_NO_STDC_NAMESPACE)
  43. using std::floor ;
  44. #endif
  45. return floor(s) ;
  46. }
  47. typedef mpl::integral_c< std::float_round_style, std::round_toward_neg_infinity> round_style ;
  48. } ;
  49. template<class S>
  50. struct Ceil
  51. {
  52. typedef S source_type ;
  53. typedef typename mpl::if_< is_arithmetic<S>,S,S const&>::type argument_type ;
  54. static source_type nearbyint ( argument_type s )
  55. {
  56. #if !defined(BOOST_NO_STDC_NAMESPACE)
  57. using std::ceil ;
  58. #endif
  59. return ceil(s) ;
  60. }
  61. typedef mpl::integral_c< std::float_round_style, std::round_toward_infinity> round_style ;
  62. } ;
  63. template<class S>
  64. struct RoundEven
  65. {
  66. typedef S source_type ;
  67. typedef typename mpl::if_< is_arithmetic<S>,S,S const&>::type argument_type ;
  68. static source_type nearbyint ( argument_type s )
  69. {
  70. // Algorithm contributed by Guillaume Melquiond
  71. #if !defined(BOOST_NO_STDC_NAMESPACE)
  72. using std::floor ;
  73. using std::ceil ;
  74. #endif
  75. // only works inside the range not at the boundaries
  76. S prev = floor(s);
  77. S next = ceil(s);
  78. S rt = (s - prev) - (next - s); // remainder type
  79. S const zero(0.0);
  80. S const two(2.0);
  81. if ( rt < zero )
  82. return prev;
  83. else if ( rt > zero )
  84. return next;
  85. else
  86. {
  87. bool is_prev_even = two * floor(prev / two) == prev ;
  88. return ( is_prev_even ? prev : next ) ;
  89. }
  90. }
  91. typedef mpl::integral_c< std::float_round_style, std::round_to_nearest> round_style ;
  92. } ;
  93. enum range_check_result
  94. {
  95. cInRange = 0 ,
  96. cNegOverflow = 1 ,
  97. cPosOverflow = 2
  98. } ;
  99. class bad_numeric_cast : public std::bad_cast
  100. {
  101. public:
  102. virtual const char * what() const throw()
  103. { return "bad numeric conversion: overflow"; }
  104. };
  105. class negative_overflow : public bad_numeric_cast
  106. {
  107. public:
  108. virtual const char * what() const throw()
  109. { return "bad numeric conversion: negative overflow"; }
  110. };
  111. class positive_overflow : public bad_numeric_cast
  112. {
  113. public:
  114. virtual const char * what() const throw()
  115. { return "bad numeric conversion: positive overflow"; }
  116. };
  117. struct def_overflow_handler
  118. {
  119. void operator() ( range_check_result r ) // throw(negative_overflow,positive_overflow)
  120. {
  121. #ifndef BOOST_NO_EXCEPTIONS
  122. if ( r == cNegOverflow )
  123. throw negative_overflow() ;
  124. else if ( r == cPosOverflow )
  125. throw positive_overflow() ;
  126. #else
  127. if ( r == cNegOverflow )
  128. ::boost::throw_exception(negative_overflow()) ;
  129. else if ( r == cPosOverflow )
  130. ::boost::throw_exception(positive_overflow()) ;
  131. #endif
  132. }
  133. } ;
  134. struct silent_overflow_handler
  135. {
  136. void operator() ( range_check_result ) {} // throw()
  137. } ;
  138. template<class Traits>
  139. struct raw_converter
  140. {
  141. typedef typename Traits::result_type result_type ;
  142. typedef typename Traits::argument_type argument_type ;
  143. static result_type low_level_convert ( argument_type s ) { return static_cast<result_type>(s) ; }
  144. } ;
  145. struct UseInternalRangeChecker {} ;
  146. } } // namespace boost::numeric
  147. #endif