Double的范围超过64位整数,但其精度不如其表示(因为double也是64位,它不能适合更多的实际值).因此,当表示较大的整数时,您开始在整数部分中失去精度.
#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; }
这打印:
2147483647 2147483647.000000 9223372036854775807 9223372036854775800.000000 2147483647 2147483648.000000
注意max int如何在不损失精度的情况下适合双精度而boost :: intmax_t(在这种情况下为64位)不能. float甚至不能持有int.
现在,问题是:在C中是否有一种方法可以检查给定整数类型的整个范围是否可以适应一个浮动点类型而不会损失精度?
最好,
>这将是一个可以在静态断言中使用的编译时检查,
>并且不会涉及枚举编译器应该知道或可以计算的常量.
解决方法
只是一个小谓词:
#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; }
测试一个T中可用的二进制精度是否存在于U.适用于所有类型.
“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>(); }