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 6 // See library home page at http://www.boost.org/libs/numeric/conversion 7 // 8 // Contact the author at: fernando_cacciola@hotmail.com 9 // 10 #ifndef BOOST_NUMERIC_CONVERSION_CONVERTER_POLICIES_FLC_12NOV2002_HPP 11 #define BOOST_NUMERIC_CONVERSION_CONVERTER_POLICIES_FLC_12NOV2002_HPP 12 13 #include <typeinfo> // for std::bad_cast 14 15 #include <boost/config/no_tr1/cmath.hpp> // for std::floor and std::ceil 16 #include <boost/throw_exception.hpp> 17 18 #include <functional> 19 20 #include "boost/type_traits/is_arithmetic.hpp" 21 22 #include "boost/mpl/if.hpp" 23 #include "boost/mpl/integral_c.hpp" 24 25 namespace boost { namespace numeric 26 { 27 28 template<class S> 29 struct Trunc 30 { 31 typedef S source_type ; 32 33 typedef typename mpl::if_< is_arithmetic<S>,S,S const&>::type argument_type ; 34 nearbyintboost::numeric::Trunc35 static source_type nearbyint ( argument_type s ) 36 { 37 #if !defined(BOOST_NO_STDC_NAMESPACE) 38 using std::floor ; 39 using std::ceil ; 40 #endif 41 42 return s < static_cast<S>(0) ? ceil(s) : floor(s) ; 43 } 44 45 typedef mpl::integral_c< std::float_round_style, std::round_toward_zero> round_style ; 46 } ; 47 48 49 50 template<class S> 51 struct Floor 52 { 53 typedef S source_type ; 54 55 typedef typename mpl::if_< is_arithmetic<S>,S,S const&>::type argument_type ; 56 nearbyintboost::numeric::Floor57 static source_type nearbyint ( argument_type s ) 58 { 59 #if !defined(BOOST_NO_STDC_NAMESPACE) 60 using std::floor ; 61 #endif 62 63 return floor(s) ; 64 } 65 66 typedef mpl::integral_c< std::float_round_style, std::round_toward_neg_infinity> round_style ; 67 } ; 68 69 template<class S> 70 struct Ceil 71 { 72 typedef S source_type ; 73 74 typedef typename mpl::if_< is_arithmetic<S>,S,S const&>::type argument_type ; 75 nearbyintboost::numeric::Ceil76 static source_type nearbyint ( argument_type s ) 77 { 78 #if !defined(BOOST_NO_STDC_NAMESPACE) 79 using std::ceil ; 80 #endif 81 82 return ceil(s) ; 83 } 84 85 typedef mpl::integral_c< std::float_round_style, std::round_toward_infinity> round_style ; 86 } ; 87 88 template<class S> 89 struct RoundEven 90 { 91 typedef S source_type ; 92 93 typedef typename mpl::if_< is_arithmetic<S>,S,S const&>::type argument_type ; 94 nearbyintboost::numeric::RoundEven95 static source_type nearbyint ( argument_type s ) 96 { 97 // Algorithm contributed by Guillaume Melquiond 98 99 #if !defined(BOOST_NO_STDC_NAMESPACE) 100 using std::floor ; 101 using std::ceil ; 102 #endif 103 104 // only works inside the range not at the boundaries 105 S prev = floor(s); 106 S next = ceil(s); 107 108 S rt = (s - prev) - (next - s); // remainder type 109 110 S const zero(0.0); 111 S const two(2.0); 112 113 if ( rt < zero ) 114 return prev; 115 else if ( rt > zero ) 116 return next; 117 else 118 { 119 bool is_prev_even = two * floor(prev / two) == prev ; 120 return ( is_prev_even ? prev : next ) ; 121 } 122 } 123 124 typedef mpl::integral_c< std::float_round_style, std::round_to_nearest> round_style ; 125 } ; 126 127 128 enum range_check_result 129 { 130 cInRange = 0 , 131 cNegOverflow = 1 , 132 cPosOverflow = 2 133 } ; 134 135 class bad_numeric_cast : public std::bad_cast 136 { 137 public: 138 what() const139 virtual const char * what() const throw() 140 { return "bad numeric conversion: overflow"; } 141 }; 142 143 class negative_overflow : public bad_numeric_cast 144 { 145 public: 146 what() const147 virtual const char * what() const throw() 148 { return "bad numeric conversion: negative overflow"; } 149 }; 150 class positive_overflow : public bad_numeric_cast 151 { 152 public: 153 what() const154 virtual const char * what() const throw() 155 { return "bad numeric conversion: positive overflow"; } 156 }; 157 158 struct def_overflow_handler 159 { operator ()boost::numeric::def_overflow_handler160 void operator() ( range_check_result r ) // throw(negative_overflow,positive_overflow) 161 { 162 #ifndef BOOST_NO_EXCEPTIONS 163 if ( r == cNegOverflow ) 164 throw negative_overflow() ; 165 else if ( r == cPosOverflow ) 166 throw positive_overflow() ; 167 #else 168 if ( r == cNegOverflow ) 169 ::boost::throw_exception(negative_overflow()) ; 170 else if ( r == cPosOverflow ) 171 ::boost::throw_exception(positive_overflow()) ; 172 #endif 173 } 174 } ; 175 176 struct silent_overflow_handler 177 { operator ()boost::numeric::silent_overflow_handler178 void operator() ( range_check_result ) {} // throw() 179 } ; 180 181 template<class Traits> 182 struct raw_converter 183 { 184 typedef typename Traits::result_type result_type ; 185 typedef typename Traits::argument_type argument_type ; 186 low_level_convertboost::numeric::raw_converter187 static result_type low_level_convert ( argument_type s ) { return static_cast<result_type>(s) ; } 188 } ; 189 190 struct UseInternalRangeChecker {} ; 191 192 } } // namespace boost::numeric 193 194 #endif 195