#include #include #include #include #include #include #include #include // std::domain_error #include #include #include #include #include namespace boost { namespace numeric { // extend to round_math template struct RoundMath { typedef SourceT source_type; typedef typename mpl::if_, SourceT, SourceT const&>::type argument_type ; typedef boost::mpl::integral_c< std::float_round_style, std::round_to_nearest > round_style; static inline source_type nearbyint(argument_type value) { #if !defined(BOOST_NO_STDC_NAMESPACE) using std::floor ; using std::ceil ; #endif return value < static_cast(0) ? ceil( value - epsilon()) : floor(value + epsilon()); } static inline source_type epsilon() { return static_cast(0.5); } }; } } //////////////////////////////////////////////////////////////////////////////// //! boost.NumericConversation range checking and overflow policies namespace core { enum range_check_result { cNonFinite = 0, cInRange = 1, cNegOverflow = 2, cPosOverflow = 3 } ; //! Define a custom range checker template struct range_checker; template struct range_checker< boost::numeric::conversion_traits, OverFlowHandler > { typedef boost::numeric::conversion_traits conv_traits; typedef typename conv_traits::argument_type argument_type; typedef typename conv_traits::source_type S; typedef typename conv_traits::target_type T; //! Check range of integral types. static inline range_check_result out_of_range(argument_type value) { // XXXX if(!boost::math::isfinite(value)) // Neither infinity nor NaN. return cNonFinite; else if(T(value) > boost::numeric::bounds::highest()) return cPosOverflow; else if(T(value) < boost::numeric::bounds::lowest()) return cNegOverflow; else return cInRange; } static void validate_range(argument_type value) { BOOST_STATIC_ASSERT(std::numeric_limits::is_bounded); OverFlowHandler()(out_of_range(value)); } }; //! Overflow handler struct bad_numeric_cast : virtual boost::exception, virtual std::bad_cast { virtual const char * what() const throw() { return "bad numeric conversion: overflow"; } }; struct non_finite : virtual boost::exception, std::domain_error { non_finite() : std::domain_error("NaN or Infinity") { } virtual const char * what() const throw() { return "bad numeric conversion: can not be represented in the target integer type"; } }; struct negative_overflow : virtual bad_numeric_cast { virtual const char * what() const throw() { return "bad numeric conversion: negative overflow"; } }; struct positive_overflow : virtual bad_numeric_cast { virtual const char * what() const throw() { return "bad numeric conversion: positive overflow"; } }; struct overflow_handler { void operator()(range_check_result result) { if(result == cNonFinite) BOOST_THROW_EXCEPTION(non_finite()); else if(result == cNegOverflow) BOOST_THROW_EXCEPTION(negative_overflow()); else if(result == cPosOverflow) BOOST_THROW_EXCEPTION(positive_overflow()); } }; } namespace boost { namespace numeric { template<> struct numeric_cast_traits { typedef double source_type; typedef double target_type; typedef conversion_traits< target_type, source_type > conv_traits; typedef core::overflow_handler overflow_policy; typedef core::range_checker< conv_traits, overflow_policy > range_checking_policy; typedef boost::numeric::RoundEven rounding_policy; }; template<> struct raw_converter> { typedef double source_type; typedef double target_type; typedef typename conversion_traits::argument_type argument_type; static target_type low_level_convert(argument_type value) { return static_cast(value); } }; }} //////////////////////////////////////////////////////////////////////////////// #include #include #include //#include typedef boost::numeric::converter MyConvert; int main() { try { { // RoundEven typedef double my_type; my_type x(1.499); my_type y(1.500); std::cout << x << "->" << MyConvert::convert(x) << '\n'; std::cout << y << "->" << MyConvert::convert(y) << '\n'; } { // RoundEven typedef double my_type; my_type x(2.499); my_type y(2.500); std::cout << x << "->" << MyConvert::convert(x) << '\n'; std::cout << y << "->" << MyConvert::convert(y) << '\n'; } } catch(core::positive_overflow& e) { std::cerr << "CORE: " << boost::diagnostic_information(e) << std::endl; } catch(boost::numeric::positive_overflow& e) { std::cerr << "Boost.Numeric: " << e.what() << std::endl; } catch(boost::exception& e) { std::cerr << "Boost: " << boost::diagnostic_information(e) << std::endl; } catch(std::exception& e) { std::cerr << "STD: " << e.what() << std::endl; } }