将积分转换为浮点类型时检测溢出

时间:2017-08-28 20:29:48

标签: c++ c floating-point language-lawyer undefined-behavior

C ++标准,据我所知,C ++也依赖于这些问题,具有以下部分:

  

当整数类型的值转换为实际浮动类型时,如果正在转换的值可以在新类型中准确表示,则它将保持不变。如果转换的值在可以表示但不能精确表示的值的范围内,则结果是以实现定义的方式选择的最接近的较高或最接近的较低可表示值。如果转换的值超出了可以表示的值范围,则行为未定义。

有什么方法可以检查最后一个案例吗?在我看来,这最后一个未定义的行为是不可避免的。如果我有一个整数值i并天真地检查

之类的东西
i <= FLT_MAX

我将(除了与精度相关的其他问题)已经触发它,因为比较首先将i转换为float(在这种情况下或通常转换为任何其他浮动类型),所以如果它超出了范围,我们得到了不确定的行为。

或者对于整数和浮动类型的相对大小有一些保证,这意味着类似于&#34;浮点数总是代表int的所有值(当然不一定完全正确)&#34;或者至少&#34; long double可以随时拥有一切&#34;以便我们可以在那种类型中进行比较?但是,我无法找到类似的东西。

这主要是一个理论练习,因此我对大多数架构的答案都不感兴趣,这些转换总是有效。&#34;。让我们试着找到一种方法来检测这种溢出而不假设超出C(++)标准! :)

2 个答案:

答案 0 :(得分:4)

  

将积分转换为浮动类型时检测溢出

FLT_MAXDBL_MAX每个C规格至少为1E + 37,所以所有整数都带有|值|在所有兼容平台上,122位或更少的位将转换为float而不会溢出。与double

相同

在128/256 /等的整数的一般情况下解决这个问题。需要减少FLT_MAXsome_big_integer_MAX位。

也许通过记录两者。 (bit_count()是TBD用户代码)

if(bit_count(unsigned_big_integer_MAX) > logbf(FLT_MAX)) problem();

或者整数缺少填充

if(sizeof(unsigned_big_integer_MAX)*CHAR_BIT > logbf(FLT_MAX)) problem();

注意:使用像logbf()这样的FP函数可能会产生一个带有精确整数数学和不正确比较的边缘条件。

宏魔法可以使用类似以下的钝角测试,BIGINT_MAX肯定是2的幂减1和FLT_MAX除以2的幂当然是确切的(除非FLT_RADIX == 10)。

如果某些大整数从大整数类型转换为float ,则抱怨 > >

#define POW2_61 0x2000000000000000u  
#if BIGINT_MAX/POW2_61 > POW2_61
  // BIGINT is at least a 122 bit integer 
  #define BIGINT_MAX_PLUS1_div_POW2_61  ((BIGINT_MAX/2 + 1)/(POW2_61/2))
  #if BIGINT_MAX_PLUS1_div_POW2_61 > POW2_61
    #warning TBD code for an integer wider than 183 bits
  #else
    _Static_assert(BIGINT_MAX_PLUS1_div_POW2_61 <= FLT_MAX/POW2_61, 
        "bigint too big for float");
  #endif
#endif

[编辑2]

  

有什么方法可以检查最后一个案例吗?

如果从大整数类型到float的转换对于选择的大整数而言不完整,此代码将抱怨

当然,在尝试转换之前,需要进行测试。

考虑到各种舍入模式或罕见的FLT_RADIX == 10,可以轻松获得的最好的测试目标有点低。如果是,则转换将起作用。然而,一个变小的范围的大整数在下面的测试中报告错误确实转换为OK。

下面是一个更精致的想法,我需要仔细考虑一下,但我希望它为OP正在寻找的测试提供了一些编码思路。

#define POW2_60 0x1000000000000000u
#define POW2_62 0x4000000000000000u
#define MAX_FLT_MIN 1e37
#define MAX_FLT_MIN_LOG2 (122 /* 122.911.. */)

bool intmax_to_float_OK(intmax_t x) {
#if INTMAX_MAX/POW2_60 < POW2_62
  (void) x;
  return true; // All big integer values work
#elif INTMAX_MAX/POW2_60/POW2_60 < POW2_62
  return x/POW2_60 < (FLT_MAX/POW2_60) 
#elif INTMAX_MAX/POW2_60/POW2_60/POW2_60 < POW2_62
  return x/POW2_60/POW2_60 < (FLT_MAX/POW2_60/POW2_60) 
#else
  #error TBD code
#endif
}

答案 1 :(得分:1)

这是一个C ++模板函数,它返回适合两种给定类型的最大正整数。

template<typename float_type, typename int_type>
int_type max_convertible()
{
    static const int int_bits = sizeof(int_type) * CHAR_BIT - std::is_signed<int_type>() ? 1 : 0;
    if ((int)ceil(std::log2(std::numeric_limits<float_type>::max())) > int_bits)
        return std::numeric_limits<int_type>::max();
    return (int_type) std::numeric_limits<float_type>::max();
}

如果您转换的数字大于此功能的返回值,则无法转换。不幸的是,我很难找到一个类型的组合来测试它,很难找到一个不适合最小浮点类型的整数类型。