如何确定给定的INT64_T是否可以无损地存储在双倍中

How to determine if a given int64_t can be stored losslessly in a double?

本文关键字:存储 何确定 INT64 是否      更新时间:2023-10-16

我想确定是否可以将给定的64位整数存储在双重中。现在我有此代码:

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

但是,由于某些平台上的精度过高,我认为这并不总是准确的。

请注意,我不是要提供最大的整数,以便所有较小的整数都可以无损地存储,即2^53。我需要知道,即使n 1和n-1不是。

标准库中是否有某些内容,也许与std::numeric_limits相似,这会告诉我?

只要低位为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;
}

从最低位设置中减去最高位,添加一个以避免围栏误差,与Mantissa中的位数相比。请记住,Mantissa的主要1是IEEE的隐含。如果Mantissa可以容纳整个使用的位,则可以准确存储该数字。

或者,查看static_cast<double>(m) != static_cast<double>(m+1) && static_cast<double>(m) != static_cast<double>(m-1)是否。这适用于 indigned 值,但是对于A 签名类型,便携式代码将需要检查该值是否不会溢出或底流,因为这是未定义的行为。再说一次,某些实现也可能没有int64_t。但是,在许多实现方面,签名的溢出或下水流仍然会给您一个不同的数字,其符号将正确测试。

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

我会争辩说,对于许多目的,您的原始方法最好:将给定的INT64_T施放为双重,然后将结果分配回第二个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;
}

我怀疑仅将new陈述宣布为挥发性就足够了,但是我不够使用挥发性的关键字来确定,所以我只是简单地从链接中调整了解决方案。

关于您的原始方法的好处是,只要您只关心是否可以回到这样的初始类型,它应该为支持正确的演员和操作员提供几乎所有支持的所有支持。例如,这是一个通用实现:

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;
}

请注意,这可能不是您问题的最佳答案,因为检查您是否可以通过...将其存储为双人物似乎仍然是一个作弊。不过,我不知道该如何避免依靠内部表示的力学。

它也不是检查它是否无损地存储在双重中,而是从INT64_T到双重的往返,然后返回INT64_T在该平台上是无损的。我不知道是否有可能出现在两个方向上应用铸造时取消的铸造错误(我会吸引更多知识的人),但是我认为,我通常认为它足够接近如果我可以转换回同一类型,则"无损"如果我可以将初始值恢复。

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