如何确定给定的int64_t是否可以无损地存储在double中?

时间:2017-03-01 20:35:32

标签: c++ precision

我想确定给定的64位整数是否可以无损地存储在double中。现在我有这个代码:

static_cast<int64_t>(static_cast<double>(value)) == value

但是,我认为由于excess precision在某些平台上,这并不总是准确的。

请注意,我没有要求largest integer such that all smaller integers can be stored losslessly,即2 ^ 53。我需要知道给定的整数N是否可以无损存储,即使N + 1和N-1不是。

标准库中是否有类似std::numeric_limits的内容,会告诉我这个?

4 个答案:

答案 0 :(得分:9)

只要低位为0,就可以设置更多的高位(因为你可以增加双指数)。我将要求减少到无符号以使位移不必担心符号位,但我认为它应该是适应性的。

bool fits_in_double_losslessly (uint64_t v)
{
    const uint64_t largest_int = 1ULL << 53;

    while ((v > largest_int) && !(v & 1))
    {
        v >>= 1;
    }

    return v <= largest_int;
}

答案 1 :(得分:2)

从最低位集减去最高位集,添加1以避免fencepost错误,与尾数中的位数进行比较。请记住,尾数中的前导1隐含在IEEE中。如果尾数可以保持使用的整个比特范围,它可以准确地存储该数字。

或者,看看static_cast<double>(m) != static_cast<double>(m+1) && static_cast<double>(m) != static_cast<double>(m-1)。这适用于 unsigned 值,但对于 signed 类型,可移植代码需要检查该值是否会溢出或下溢,因为这是未定义的行为。然后,一些实现可能也没有int64_t。但是,在许多实现中,有符号的溢出或下溢仍会为您提供不同的数字,并且符号相反,这将正确地测试为不同。

答案 2 :(得分:1)

其他答案中的一个共同主题是关于您是否可以假设双打是否通过IEEE 754实现的问题。

我认为,出于很多目的,你的原始方法是最好的:将给定的int64_t转换为double,然后将结果返回给第二个int64_t,并比较两者。

关于过度精度的问题,只要您知道该值实际上已写入内存并回读,就不应该适用,因为在那个阶段编译器不应该存储任何方式该变量的“超精确度”。基于原始链接的答案,我相信以下示例足以强制执行此行为:

bool losslessRoundTrip(int64_t valueToTest)
{
    double newRepresentation;
    *((volatile double *)&newRepresentation) = static_cast<double>(valueToTest);
    int64_t roundTripValue = static_cast<int64_t>(newRepresentation);
    return roundTripValue == valueToTest;
}

我怀疑只是将newRepresentation声明为volatile是足够的,但我没有足够使用volatile关键字,所以我只是简单地从你的链接调整了解决方案。

关于你的原始方法的好处是,它应该适用于支持正确的强制转换和运算符的任何东西,只要你只关心你是否可以回到这样的初始类型。例如,这是一个通用实现:

template<typename T1, typename T2>
bool losslessRoundTrip(T1 valueToTest)
{
    T2 newRepresentation;
    *((volatile T2 *)&newRepresentation) = static_cast<T2>(valueToTest);
    T1 roundTripValue = static_cast<T1>(newRepresentation);
    return roundTripValue == valueToTest;
}

请注意,这可能不是您问题的最佳答案,因为检查您是否可以将其存储为双倍,这仍然是一个骗子...将其存储为双倍。不过,我不知道如何避免依赖内部代表的机制。

它也不会完全检查它是否无损地存储在double中,而是从int64_t到double的往返并返回到int64_t是否在该平台上是无损的。我不知道是否有可能在两个方向上施放演员阵容时出现错误的投射错误(我会吸引那些对此有更多了解的人),但在我看来,我通常认为它足够接近如果我转换回相同的类型,如果我可以获得初始值,那么“无损”。

答案 3 :(得分:-3)

您需要测试较低位。如果它们为零,则该数字将无损存储。