Line data Source code
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 : 36 0 : 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 0 : 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 : 58 : 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 : 77 : 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 : 96 : 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 : 140 0 : virtual const char * what() const BOOST_NOEXCEPT_OR_NOTHROW 141 0 : { return "bad numeric conversion: overflow"; } 142 : }; 143 : 144 : class negative_overflow : public bad_numeric_cast 145 : { 146 : public: 147 : 148 0 : virtual const char * what() const BOOST_NOEXCEPT_OR_NOTHROW 149 0 : { return "bad numeric conversion: negative overflow"; } 150 : }; 151 : class positive_overflow : public bad_numeric_cast 152 : { 153 : public: 154 : 155 0 : virtual const char * what() const BOOST_NOEXCEPT_OR_NOTHROW 156 0 : { return "bad numeric conversion: positive overflow"; } 157 : }; 158 : 159 : struct def_overflow_handler 160 : { 161 : 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 : { 179 : 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 : 188 0 : 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