有效的浮点比较

时间:2013-05-28 10:00:58

标签: c++ c performance floating-point

嗨我有一个定义为

的函数
int compareAB(float A, float B)  
{  
    if(A > B) 
    {  
        return 1;  
    }
    else if(A < B)
    {
        return -1;  
    }  
    else
    {
        return 0;
    }
}

以上功能在我的项目中进行比较需要花费太多时间,我可以从性能工具中看到。我可以改善它的运行时间。

我认为的一种方法是将2个数字相差,然后将其与零进行比较。

谢谢,

编辑:此功能用于排序比较功能,用于维护搜索树数据结构。现在也更正了返回值。

3 个答案:

答案 0 :(得分:4)

这看起来像是试图规避“永远不应该比较浮点上的相等”规则的一种人为的方式。比较不等式与比较相等性并没有太大的不同,因为在两种情况下都依赖于浮点精度。你的最后'else'语句是一个隐含的A == B.

正常成语是if (::fabs(A - B) < e),其中e是一定容差,但在您的情况下,您不需要::fabs

如果你想要正面,负面和相等的不同结果(在计算精度的限度内),那么做类似的事情

if (A - B > e){
    return 0;
} else if (A - B < -e){
    return 1;
} else {
    return -1;
}

你可以期待的最好的是将e设置为std::numeric_limits<double>::epsilon()。实际值取决于为了到达A和B而执行的计算步骤的数量.1e-08可能是现实的。

至于速度,不幸的是它:我看不出这是瓶颈或跑得更快。

答案 1 :(得分:0)

这里的一个问题是返回值完全不正确。第一个返回值应为1,第二个应为-1,第三个应为零。如果您使用它进行排序,排序可能不稳定,这会增加其运行时间。

原则上,您只需返回a-b,除非您打算处理NaN

答案 2 :(得分:-1)

浮点比较可能比普通整数比较昂贵,特别是如果没有专用的浮点硬件。

幸运的是,在比较浮点数时,您可以使用整数比较,在某些情况下:

1)这仅在使用IEEE754浮点格式时有效。 2)它不适用于NaN:s。

访问底层表示是未定义的行为,因为C语言没有指定它使用哪种浮点格式。

无论如何,诀窍在于它只有在浮点数具有相同符号时才有效。并且,在这种情况下,比较两个浮点数的整数表示是比较浮点数本身的

我的性能没有测量下面的代码,但可能是它比原始代码快。如果有的话,请告诉我性能提升!

int compareAB(float a_orig, float b_orig)
{
  /* Get the underlying representation of A and B. */
  long a = *(unsigned long *)&a_orig;
  long b = *(unsigned long *)&b_orig;

  if (a < 0)
  {
    if (b < 0)
    {
      /* Both are negative. The order of the integer representation is
       * the OPPOSITE of the order of the floating-point value. */
      if (a > b)
      {
        return -1;
      }
      else if (a < b)
      {
        return 1;
      }
      else
      {
        return 0;
      }
    }
    else
    {
      /* A is negative, B isn't => A is smaller. */
      return -1;
    }
  }
  else if (b < 0)
  {
    /* B is negative, A isn't => B is smaller. */
    return 1;
  }
  else
  {
    /* Both are positive. */
    if (a > b)
    {
      return 1;
    }
    else if (a < b)
    {
      return -1;
    }
    else
    {
      return 0;
    }
  }
}

你可以用以下方法测试:

#include <stdio.h>

float values[] = {-100.0F,
                  -50.0F,
                  0.0F,
                  50.0F,
                  100.0F };

void test(float a, float b)
{
  const char * p = 0;
  printf("%f is ", a);

  switch (compareAB(a, b))
  {
  case -1: p = "smaller than"; break;
  case  0: p = "equal to"; break;
  case  1: p = "greater than"; break;
  }

  printf("%s %f\n", p, b);
}

int main(void)
{
  int i;

  for (i = 0; i < sizeof(values)/sizeof(values[0]); ++i)
  {
    int j;
    for (j = 0; j < sizeof(values)/sizeof(values[0]); ++j)
    {
      test(values[i], values[j]);
    }
  }
}

它提供与使用原始代码时相同的输出,即:

-100.000000 is equal to -100.000000
-100.000000 is smaller than -50.000000
-100.000000 is smaller than 0.000000
-100.000000 is smaller than 50.000000
-100.000000 is smaller than 100.000000
-50.000000 is greater than -100.000000
-50.000000 is equal to -50.000000
-50.000000 is smaller than 0.000000
-50.000000 is smaller than 50.000000
-50.000000 is smaller than 100.000000
0.000000 is greater than -100.000000
0.000000 is greater than -50.000000
0.000000 is equal to 0.000000
0.000000 is smaller than 50.000000
0.000000 is smaller than 100.000000
50.000000 is greater than -100.000000
50.000000 is greater than -50.000000
50.000000 is greater than 0.000000
50.000000 is equal to 50.000000
50.000000 is smaller than 100.000000
100.000000 is greater than -100.000000
100.000000 is greater than -50.000000
100.000000 is greater than 0.000000
100.000000 is greater than 50.000000
100.000000 is equal to 100.000000