Re: Float/Double compare

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Ian Rogers wrote:
public static int compare(float x, float y)
  {
    if (isNaN(x))
      return isNaN(y) ? 0 : 1;
   if (isNaN(y))
      return -1;
    // recall that 0.0 == -0.0, so we convert to infinities and try again
    if (x == 0 && y == 0)
      return (int) (1 / x - 1 / y);
    if (x == y)
      return 0;
    return x > y ? 1 : -1;
  }
Below is a variant of the compare code and a comparison with the cost of the current compare code:

public static int compare(float x, float y)
{
  int ix = floatAsIntBits(x);
  int iy = floatAsIntBits(y);
  if (ix == iy) return 0;
  if (isNaN(x)) return 1;
  if (isNaN(y)) return -1;
  int ix_sign = ix>>31;
  int iy_sign = iy>>31;
  if (ix_sign == iy_sign) {
    return x > y ? 1 : -1;
  } else {
    return ix_sign - iy_sign;
  }
}

Case: x == y neither are NaN or 0.0
New Cost: 2 float as ints, 1 int compare
Old Cost: 5 float compares

Case: x < y and different sign
New Cost: 2 float as ints, 2 int compares, 2 float compares, 2 shifts, one subtract
Old Cost: 6 float compares

Case: x < y and same sign
New Cost: 2 float as ints, 2 int compares, 3 float compares, 2 shifts
Old Cost: 6 float compares

Case: x is NaN
New Cost: 2 float as ints, 1 int compare, 1 float compare
Old Cost: 2 float compares

Case: y is NaN
New Cost: 2 float as ints, 1 int compare, 2 float compares
Old Cost: 2 float compares

Case: x == 0.0 and y == 0.0
New Cost: either 2 float as ints, 1 int compare or 2 float as ints, 2 int compares, 2 float compares, 2 shifts, one subtract Old Cost: 4 float compares, 2 float divides, 1 float subtract, 1 float to int

The same code but for doubles would be:

public static int compare(double x, double y)
{
  long lx = doubleAsLongBits(x);
  long ly = doubleAsLongBits(y);
  if (lx == ly) return 0;
  if (isNaN(x)) return 1;
  if (isNaN(y)) return -1;
  int lx_sign = (int)(lx>>63);
  int ly_sign = (int)(ly>>63);
  if (lx_sign == ly_sign) {
    return x > y ? 1 : -1;
  } else {
    return lx_sign - ly_sign;
  }
}

So the case when y is a NaN is slower with the new code but I think all of the more common cases are similar or faster. Of course it depends on the speed of all the operations. If you cared about a CPU with no floating point, the new code is a lot faster. If you've got great floating point and a lot of cases of y being a NaN the old code will be better. My guess is that in the general case the new code wins out. There may be a bug I can't see in this code :-)

Regards,
Ian


[Index of Archives]     [Linux Kernel]     [Linux Cryptography]     [Fedora]     [Fedora Directory]     [Red Hat Development]

  Powered by Linux