williamr@2: // © Copyright Fernando Luis Cacciola Carballal 2000-2004 williamr@2: // Use, modification, and distribution is subject to the Boost Software williamr@2: // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at williamr@2: // http://www.boost.org/LICENSE_1_0.txt) williamr@2: williamr@2: // See library home page at http://www.boost.org/libs/numeric/conversion williamr@2: // williamr@2: // Contact the author at: fernando_cacciola@hotmail.com williamr@2: // williamr@2: #ifndef BOOST_NUMERIC_CONVERSION_CONVERTER_POLICIES_FLC_12NOV2002_HPP williamr@2: #define BOOST_NUMERIC_CONVERSION_CONVERTER_POLICIES_FLC_12NOV2002_HPP williamr@2: williamr@2: #include // for std::bad_cast williamr@2: williamr@2: #include // for std::floor and std::ceil williamr@2: williamr@2: #include williamr@2: williamr@2: #include "boost/type_traits/is_arithmetic.hpp" williamr@2: williamr@2: #include "boost/mpl/if.hpp" williamr@2: #include "boost/mpl/integral_c.hpp" williamr@2: williamr@2: namespace boost { namespace numeric williamr@2: { williamr@2: williamr@2: template williamr@2: struct Trunc williamr@2: { williamr@2: typedef S source_type ; williamr@2: williamr@2: typedef typename mpl::if_< is_arithmetic,S,S const&>::type argument_type ; williamr@2: williamr@2: static source_type nearbyint ( argument_type s ) williamr@2: { williamr@2: #if !defined(BOOST_NO_STDC_NAMESPACE) williamr@2: using std::floor ; williamr@2: using std::ceil ; williamr@2: #endif williamr@2: williamr@2: return s < static_cast(0) ? ceil(s) : floor(s) ; williamr@2: } williamr@2: williamr@2: typedef mpl::integral_c< std::float_round_style, std::round_toward_zero> round_style ; williamr@2: } ; williamr@2: williamr@2: williamr@2: williamr@2: template williamr@2: struct Floor williamr@2: { williamr@2: typedef S source_type ; williamr@2: williamr@2: typedef typename mpl::if_< is_arithmetic,S,S const&>::type argument_type ; williamr@2: williamr@2: static source_type nearbyint ( argument_type s ) williamr@2: { williamr@2: #if !defined(BOOST_NO_STDC_NAMESPACE) williamr@2: using std::floor ; williamr@2: #endif williamr@2: williamr@2: return floor(s) ; williamr@2: } williamr@2: williamr@2: typedef mpl::integral_c< std::float_round_style, std::round_toward_neg_infinity> round_style ; williamr@2: } ; williamr@2: williamr@2: template williamr@2: struct Ceil williamr@2: { williamr@2: typedef S source_type ; williamr@2: williamr@2: typedef typename mpl::if_< is_arithmetic,S,S const&>::type argument_type ; williamr@2: williamr@2: static source_type nearbyint ( argument_type s ) williamr@2: { williamr@2: #if !defined(BOOST_NO_STDC_NAMESPACE) williamr@2: using std::ceil ; williamr@2: #endif williamr@2: williamr@2: return ceil(s) ; williamr@2: } williamr@2: williamr@2: typedef mpl::integral_c< std::float_round_style, std::round_toward_infinity> round_style ; williamr@2: } ; williamr@2: williamr@2: template williamr@2: struct RoundEven williamr@2: { williamr@2: typedef S source_type ; williamr@2: williamr@2: typedef typename mpl::if_< is_arithmetic,S,S const&>::type argument_type ; williamr@2: williamr@2: static source_type nearbyint ( argument_type s ) williamr@2: { williamr@2: // Algorithm contributed by Guillaume Melquiond williamr@2: williamr@2: #if !defined(BOOST_NO_STDC_NAMESPACE) williamr@2: using std::floor ; williamr@2: using std::ceil ; williamr@2: #endif williamr@2: williamr@2: // only works inside the range not at the boundaries williamr@2: S prev = floor(s); williamr@2: S next = ceil(s); williamr@2: williamr@2: S rt = (s - prev) - (next - s); // remainder type williamr@2: williamr@2: S const zero(0.0); williamr@2: S const two(2.0); williamr@2: williamr@2: if ( rt < zero ) williamr@2: return prev; williamr@2: else if ( rt > zero ) williamr@2: return next; williamr@2: else williamr@2: { williamr@2: bool is_prev_even = two * floor(prev / two) == prev ; williamr@2: return ( is_prev_even ? prev : next ) ; williamr@2: } williamr@2: } williamr@2: williamr@2: typedef mpl::integral_c< std::float_round_style, std::round_to_nearest> round_style ; williamr@2: } ; williamr@2: williamr@2: williamr@2: enum range_check_result williamr@2: { williamr@2: cInRange = 0 , williamr@2: cNegOverflow = 1 , williamr@2: cPosOverflow = 2 williamr@2: } ; williamr@2: williamr@2: class bad_numeric_cast : public std::bad_cast williamr@2: { williamr@2: public: williamr@2: williamr@2: virtual const char * what() const throw() williamr@2: { return "bad numeric conversion: overflow"; } williamr@2: }; williamr@2: williamr@2: class negative_overflow : public bad_numeric_cast williamr@2: { williamr@2: public: williamr@2: williamr@2: virtual const char * what() const throw() williamr@2: { return "bad numeric conversion: negative overflow"; } williamr@2: }; williamr@2: class positive_overflow : public bad_numeric_cast williamr@2: { williamr@2: public: williamr@2: williamr@2: virtual const char * what() const throw() williamr@2: { return "bad numeric conversion: positive overflow"; } williamr@2: }; williamr@2: williamr@2: struct def_overflow_handler williamr@2: { williamr@2: void operator() ( range_check_result r ) // throw(negative_overflow,positive_overflow) williamr@2: { williamr@2: if ( r == cNegOverflow ) williamr@2: throw negative_overflow() ; williamr@2: else if ( r == cPosOverflow ) williamr@2: throw positive_overflow() ; williamr@2: } williamr@2: } ; williamr@2: williamr@2: struct silent_overflow_handler williamr@2: { williamr@2: void operator() ( range_check_result ) {} // throw() williamr@2: } ; williamr@2: williamr@2: template williamr@2: struct raw_converter williamr@2: { williamr@2: typedef typename Traits::result_type result_type ; williamr@2: typedef typename Traits::argument_type argument_type ; williamr@2: williamr@2: static result_type low_level_convert ( argument_type s ) { return static_cast(s) ; } williamr@2: } ; williamr@2: williamr@2: struct UseInternalRangeChecker {} ; williamr@2: williamr@2: } } // namespace boost::numeric williamr@2: williamr@2: #endif