检查float是否可以表示为整型

Check if float can be represented as integral type

本文关键字:表示 整型 float 是否 检查      更新时间:2023-10-16

如何检查float是否可以表示为整数类型,而不需要通过强制转换调用未定义行为?这是§4.9.1所禁止的:

浮点型的右值可以转换为an型的右值整数类型。转换截断;也就是小数部分就会被丢弃。如果截断的值不能,则行为未定义以目标类型

表示

对于C来说有这个问题,但是被接受的答案显然会导致未定义的行为(首先是通过简单的强制转换,然后通过使用union hack,这使得整个事情对我来说非常可疑)。

我可以看到有一个完全兼容的解决方案是多么困难,但是一个实现定义的(假设IEEE-754浮动)也是可以接受的。

检查truncf(x) == x。(函数在<math.h>中)当且仅当x没有小数部分时,将比较true。然后,将x与类型的范围进行比较。

示例代码(未测试)

#include <cfenv>
#include <cmath>
#pragma STDC FENV_ACCESS on
template<class F, class N> // F is a float type, N integral.
  bool is_representable(const F x)
{
  const int orig_rounding = std::fegetround();
  std::fesetround(FE_TOWARDZERO);
  const bool to_return = std::trunc(x) == x &&
                         x >= std::numeric_limits<N>.min() &&
                         x <= std::numeric_limits<N>.max();
  std::fesetround(orig_rounding);
  return to_return;
}

舍入设置为0时,将整型的最小值和最大值隐式转换为浮点型时不会溢出。在包括i386在内的许多体系结构上,转换为long double也将提供足够的精度来精确表示64位int。

您可以使用snprintf()中的%a格式类型说明符来访问尾数和指数,然后您可以计算出该数字是否是整数,以及它是否适合特定大小的整数类型。我在另一个问题中使用了这个方法。

考虑从1到MAX_FLOAT的正整数。对于ieee754指数表示2的幂(它以偏置存储)。ieee -754格式使用1个符号位,8个有偏指数位和23个尾数位。的尾数是这个数的阶乘部分。最高位是1/2,接下来是1/4,接下来是1/8……

1 ~ 1.999…有相同的指数。(1)

范围内有1个整数

2 ~ 3.999…有相同的指数。在(2,3)范围内有2个整数。3有最高的尾数位,所以它需要前导尾数位。如果任何其他低尾数位是,那么它不是整数。因为它是2或3加上小数位的值

从4到7.999…有相同的指数。范围内有4个整数(4,5,6,7)它们使用最高的2个尾数位。如果设置了其他尾数位,则它不是整数。

8 ~ 15.999…有相同的指数。范围内有8个整数(8,9,10,11,12,13,14,15)这些使用3个最高尾数位。如果设置了其他尾数位,则它不是整数。

我希望你能看到的模式,当你增加指数,可能的整数的数量加倍。因此,忽略n个最高尾数位,并测试是否设置了最低尾数位。如果是,则该数字不是整数。

这个表显示了常数指数值0x40加上下一个最高位,并且只有整数的高阶尾数位被设置

Float    Hex
4        0x40800000
5        0x40a00000
6        0x40c00000
7        0x40e00000

将浮点数转换为UInt32

float x  = 7.0;
UInt32 * px = (UInt32*)&x;
UInt32    i = *px;