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