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 <functional> 14 : #include <typeinfo> // for std::bad_cast 15 : 16 : #include <boost/config.hpp> 17 : #include <boost/config/no_tr1/cmath.hpp> // for std::floor and std::ceil 18 : #include <boost/throw_exception.hpp> 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 : 35 : 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 : 57 : 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 : 76 : 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 : 95 : 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 : 139 : const char * what() const BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE 140 : { return "bad numeric conversion: overflow"; } 141 : }; 142 : 143 : class negative_overflow : public bad_numeric_cast 144 : { 145 : public: 146 : 147 : const char * what() const BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE 148 : { return "bad numeric conversion: negative overflow"; } 149 : }; 150 : class positive_overflow : public bad_numeric_cast 151 : { 152 : public: 153 : 154 : const char * what() const BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE 155 : { return "bad numeric conversion: positive overflow"; } 156 : }; 157 : 158 : struct def_overflow_handler 159 : { 160 : 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 : { 178 : 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 : 187 14 : 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