且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何检查float是否可以精确地表示为整数

更新时间:2023-11-30 23:03:16

这是一种在大多数情况下可以工作的方法。我不知道如果你给它,它将如何/将如何破坏 NaN INF ,非常大(溢出)数字...

(虽然我认为他们都会返回错误 - 不能完全代表。)

Here's one method that could work in most cases. I'm not sure if/how it will break if you give it NaN, INF, very large (overflow) numbers...
(Though I think they will all return false - not exactly representable.)

您可以:


  1. 将其转换为整数。

  2. 将其转换为浮点。

  3. 与原始价值比较

如下所示:

double val = ... ;  //  Value

if ((double)(long long)val == val){
    //  Exactly representable
}

floor() ceil()也是公平的游戏(尽管它们可能会失败,如果值溢出一个整数):

floor() and ceil() are also fair game (though they may fail if the value overflows an integer):

floor(val) == val
ceil(val) == val






这是一个凌乱的位掩码解决方案:

这使用联合类型惩罚,并假定IEEE双精度。 联盟类型仅在C99 TR2及更高版本中有效。

int representable(double x){
    //  Handle corner cases:
    if (x == 0)
      return 1;

    //  -2^63 is representable as a signed 64-bit integer, but +2^63 is not.
    if (x == -9223372036854775808.)
      return 1;

    //  Warning: Union type-punning is only valid in C99 TR2 or later.
    union{
        double f;
        uint64_t i;
    } val;

    val.f = x;

    uint64_t exp = val.i & 0x7ff0000000000000ull;
    uint64_t man = val.i & 0x000fffffffffffffull;
    man |= 0x0010000000000000ull;  //  Implicit leading 1-bit.

    int shift = (exp >> 52) - 1075;
    //  Out of range
    if (shift < -52 || shift > 10)
        return 0;

    //  Test mantissa
    if (shift < 0){
        shift = -shift;
        return ((man >> shift) << shift) == man;
    }else{
        return ((man << shift) >> shift) == man;
    }
}