【问题标题】:Find max integer size that a floating point type can handle without loss of precision查找浮点类型可以在不损失精度的情况下处理的最大整数大小
【发布时间】:2010-04-06 00:52:27
【问题描述】:

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 如何在不损失精度的情况下适合 doubleboost::intmax_t(在这种情况下为 64 位)不能。 float 甚至不能持有 int

现在,问题是:在 C++ 中有没有一种方法可以检查给定整数类型的整个范围是否可以在不损失精度的情况下适合浮点类型?

最好,

  • 这将是一个可用于静态断言的编译时检查,
  • 并且不会涉及枚举编译器应该知道或可以计算的常量。

【问题讨论】:

  • 为什么要检查?整数部分有 52 位精度,这就是你得到的。
  • 一旦确定了限制,就不能定义一个 CONST 吗?
  • @Billy:技术上 C++ 不需要 IEEE 754 浮点,因此假设实现使用 IEEE 754 是不可移植的(尽管 IEEE 754 无处不在)。
  • @Billy ONeal,我已经更新了问题。

标签: c++ floating-point double precision


【解决方案1】:

只是一个小谓词:

#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 中。适用于所有类型。


“增强”:

// 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>();
}

【讨论】:

    【解决方案2】:

    您可以使用std::numeric_limits&lt;T&gt;::digits 了解您的二进制精度。例如:

    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
    

    【讨论】:

    • 我正在使用 VC,这就是为什么你在我的回答中看到 long long 虽然它还不是标准的。
    • long long 也被 GCC 和 ICC 接受。我相信 DMC 和其他一些人也会这样做。这是一个非常常见的扩展。
    • 至少比使用 __int64 好。
    猜你喜欢
    • 2019-01-01
    • 1970-01-01
    • 2016-12-06
    • 2018-07-09
    • 1970-01-01
    • 2019-09-22
    • 2018-10-14
    • 1970-01-01
    相关资源
    最近更新 更多