符合标准的方法来比较浮点数和积分值?

时间:2015-04-27 02:44:45

标签: c++ floating-point integer comparison language-lawyer

假设我有两个对象if的{​​{1}}和I对象。我知道F是真的,std::is_integral<I>::value是真的。

是否有完全符合标准的方式来确定std::is_floating_point<F>::value的值是否小于i的值?请注意强调“完全符合标准”,对于这个问题,我只对C ++标准保证支持的答案感兴趣。

琐碎的实施f不起作用,因为i < I(f)的值可能不适合f。琐碎的实现i也不起作用,因为F(i) < f的精确度可能不足以表示f,导致i四舍五入到等于{的值{1}}(如果您有IEEE754浮点数,i失败)。

但是真正的困境是:如果你想使用f来缓解这些问题,那么你回到最初的比较浮点数和整数的问题!这是因为16777219 < 16777220.f的类型等于原始类型。

2 个答案:

答案 0 :(得分:2)

  1. 如果f超出I的范围,您可以通过其符号告诉结果。

  2. 如果fI的范围内但是太大而没有小数部分,请将其作为整数进行比较。

  3. 否则,将i转换为F是安全的,因为舍入不会改变比较结果:f已经小于任何值I将被舍入。

  4. template< typename I, typename F >
    std::enable_if_t< std::is_integral_v< I > && std::is_floating_point_v< F >,
    bool > less( I i, F f ) {
        // Return early for operands of different signs.
        if ( i < 0 != f < 0 ) return i < 0;
    
        bool rev = i >= 0;
        if ( rev ) {
            f = - f; // Make both operands non-positive.
            i = - i; // (Negativity avoids integer overflow here.)
        }
    
        if ( f < /* (F) */ std::numeric_limits<I>::min() ) {
            // |i| < |f| because f is outside the range of I.
            return rev;
        }
        if ( f * std::numeric_limits<F>::epsilon() <= -1 ) {
            // f must be an integer (in I) because of limited precision in F.
            I fi = f;
            return rev? fi < i : i < fi;
        }
        // |f| has better than integer precision.
        // If (F) |i| loses precision, it will still be greater than |f|.
        return rev? f < i : i < f;
    }
    

    演示:http://coliru.stacked-crooked.com/a/b5c4bea14bc09ee7

答案 1 :(得分:0)

我就是这样做的:

我认为f是有限的,无限和NaN的情况将在别处处理。

  1. 比较f和F(i),如果不相等,你就完成了,f和i要么是&lt;或&gt;

  2. 如果相等,则比较I(f)和i

  3. 唯一的假设是:

    • 如果浮点数具有恰好值i,则F(i)给出该值

    • 如果有一个整数与f具有完全相同的值,则I(f)给出该值

    • 函数F和I的单调性

    修改

    更明确地说,上面的技巧是用于编写比较函数,而不仅仅是测试相等...

    floatType F(intType i);
    intType I(floatType f);
    int cmpfi(floatType f,intType i)
    {
      assert(isfinite(f));
      if(f < F(i)) return -1;
      if(f == F(i))
      {
        if( I(f) < i ) return -1;
        return I(f) > i;
      }
      return 1;
    }
    

    由您决定将此草稿转换为可以处理多个不同floatType / intType

    的C ++代码