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

时间:2015-09-27 17:49:53

标签: c++ undefined-behavior

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

  

浮点类型的prvalue可以转换为a的prvalue   整数类型。转换截断;也就是说,小数部分   被丢弃了。如果截断值不能,则行为未定义   用目的地类型表示,

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

我可以看到如何拥有一个完全合规的解决方案,但是实现定义的一个(假设IEEE-754浮点数)也是可以接受的。

3 个答案:

答案 0 :(得分:0)

检查truncf(x) == x。 (该函数位于<math.h>)当且仅当 x 没有小数部分时,这将比较真。然后,将 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;
}

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

答案 1 :(得分:0)

您可以使用snprintf()中的palindrome?格式类型说明符来访问尾数和指数,然后您可以计算出数字是否为整数以及是否适合特定大小的整数类型。我在different problem中使用了这种方法。

答案 2 :(得分:0)

让我们考虑从1到MAX_FLOAT的正整数。对于IEEE 754指数表示2的幂(它以偏差存储)。 IEE-754格式使用1个符号位,8个偏置指数位和23个尾数位。尾数 是数字的派系部分。最高位是1/2,下一个1/4,下一个1/8 ......

1到1.999之间的数字......具有相同的指数。范围(1)

中有1个整数

2到3.999之间的数字......具有相同的指数。范围内有2个整数(2,3)。 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;