Hi,Quoting the docs for boost::numeric_cast: "There are several situations where conversions are unsafe: [...] Conversions from floating point types to integral types."What about conversions from integral types to floating point types? E.g. from 64bit int to double.The following example shows what I mean:#include <iostream>#include <cmath>#include <boost/numeric/conversion/cast.hpp>int main(){const uint64_t i = 123445678911188878;std::cout << "i=" << i << std::endl;const double d = i;std::cout << "d=" << std::fixed << d << std::endl;std::cout << "next=" << std::fixed << std::nextafter(d, std::numeric_limits<double>::max() ) << std::endl;std::cout << "prev=" << std::fixed << std::nextafter(d, -std::numeric_limits<double>::max()) << std::endl;// I'd expect the following cast to failconst double dd = boost::numeric_cast<double>(i);std::cout <<"dd=" << std::fixed << dd << std::endl;return 0;}printsi=123445678911188878d=123445678911188880.000000next=123445678911188896.000000prev=123445678911188864.000000dd=123445678911188880.000000because that integer cannot be represented in double precision
Is there something in Boost to help here?
template<class Traits> |
struct precise_converter |
{ |
typedef typename Traits::result_type result_type ; |
typedef typename Traits::argument_type argument_type ; |
|
static result_type low_level_convert ( argument_type s ) { const result_type res = static_cast<result_type>(s) ; if (std::abs(s - res) >= 1) { throw std::runtime_error("precision loss"); } return res; } |
} ; |
template <typename Target, typename Source> inline Target precise_numeric_cast( Source arg ) // use this instead of numeric_cast { typedef numeric::conversion_traits<Target, Source> conv_traits; typedef numeric::numeric_cast_traits<Target, Source> cast_traits; typedef boost::numeric::converter < Target, Source, conv_traits, typename cast_traits::overflow_policy, typename cast_traits::rounding_policy,
/* only the following line differs from the original numeric_cast*/ precise_converter< conv_traits >, typename cast_traits::range_checking_policy > converter; return converter::convert(arg); }