Find the maximum integer size that a floating point type can handle without loss of precision

Double has a range greater than a 64-bit integer, but its accuracy is less than its representation (since double is also 64-bit, it cannot correspond to more real values). Thus, when representing large integers, you begin to lose precision in the integer part.

#include <boost/cstdint.hpp> #include <limits> template<typename T, typename TFloat> void maxint_to_double() { T i = std::numeric_limits<T>::max(); TFloat d = i; std::cout << std::fixed << i << std::endl << d << std::endl; } int main() { maxint_to_double<int, double>(); maxint_to_double<boost::intmax_t, double>(); maxint_to_double<int, float>(); return 0; } 

Fingerprints:

 2147483647 2147483647.000000 9223372036854775807 9223372036854775800.000000 2147483647 2147483648.000000 

Note how max int can fit into double without loss of precision, and boost::intmax_t (in this case 64-bit) cannot. float cannot even contain int .

Now the question is: is there a way in C ++ to check whether the entire range of a given integer type can fit into the loating point type without loss of precision?

Preferably,

  • it will be a compile-time check that can be used in a static statement,
  • and will not include an enumeration of constants that the compiler needs to know or can calculate.
+6
c ++ double floating-point precision
source share
2 answers

Just a predicate:

 #include <limits> template <typename T, typename U> struct can_fit { static const bool value = std::numeric_limits<T>::digits <= std::numeric_limits<U>::digits; }; #include <iostream> int main(void) { std::cout << std::boolalpha; std::cout << can_fit<short, float>::value << std::endl; std::cout << can_fit<int, float>::value << std::endl; std::cout << can_fit<int, double>::value << std::endl; std::cout << can_fit<long long, double>::value << std::endl; std::cout << can_fit<short, int>::value << std::endl; std::cout << can_fit<int, short>::value << std::endl; } 

Checks if binary precision exists in T in U Works on all types.


"Boostified":

 // this is just stuff I use #include <boost/type_traits/integral_constant.hpp> template <bool B> struct bool_type : boost::integral_constant<bool, B> { static const bool value = B; }; typedef const boost::true_type& true_tag; typedef const boost::false_type& false_tag; // can_fit type traits #include <limits> namespace detail { template <typename T, typename U> struct can_fit { static const bool value = std::numeric_limits<T>::digits <= std::numeric_limits<U>::digits; }; } template <typename T, typename U> struct can_fit : bool_type<detail::can_fit<T, U>::value> { typedef T type1; typedef U type2; static const bool value = detail::can_fit<T, U>::value; }; // test #include <iostream> namespace detail { void foo(true_tag) { std::cout << "T fits in U" << std::endl; } void foo(false_tag) { std::cout << "T does not fit in U" << std::endl; } } // just an example template <typename T, typename U> void foo(void) { detail::foo(can_fit<T, U>()); } int main(void) { foo<int, double>(); } 
+6
source share

You can use std::numeric_limits<T>::digits to find out how much binary precision you have. eg:

 int binary_digits_double = numeric_limits<double>::digits; // 53 int binary_digits_long_long = numeric_limits<long long>::digits; // 63 int binary_digits_uint = numeric_limits<unsigned int>::digits; // 32 
+5
source share

All Articles