Fastest way to determine if an integer's square root is an integer

前端 未结 30 1717
心在旅途
心在旅途 2020-11-22 02:17

I\'m looking for the fastest way to determine if a long value is a perfect square (i.e. its square root is another integer):

  1. I\'ve done it the ea
30条回答
  •  遥遥无期
    2020-11-22 03:03

    I was thinking about the horrible times I've spent in Numerical Analysis course.

    And then I remember, there was this function circling around the 'net from the Quake Source code:

    float Q_rsqrt( float number )
    {
      long i;
      float x2, y;
      const float threehalfs = 1.5F;
    
      x2 = number * 0.5F;
      y  = number;
      i  = * ( long * ) &y;  // evil floating point bit level hacking
      i  = 0x5f3759df - ( i >> 1 ); // wtf?
      y  = * ( float * ) &i;
      y  = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
      // y  = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
    
      #ifndef Q3_VM
      #ifdef __linux__
        assert( !isnan(y) ); // bk010122 - FPE?
      #endif
      #endif
      return y;
    }
    

    Which basically calculates a square root, using Newton's approximation function (cant remember the exact name).

    It should be usable and might even be faster, it's from one of the phenomenal id software's game!

    It's written in C++ but it should not be too hard to reuse the same technique in Java once you get the idea:

    I originally found it at: http://www.codemaestro.com/reviews/9

    Newton's method explained at wikipedia: http://en.wikipedia.org/wiki/Newton%27s_method

    You can follow the link for more explanation of how it works, but if you don't care much, then this is roughly what I remember from reading the blog and from taking the Numerical Analysis course:

    • the * (long*) &y is basically a fast convert-to-long function so integer operations can be applied on the raw bytes.
    • the 0x5f3759df - (i >> 1); line is a pre-calculated seed value for the approximation function.
    • the * (float*) &i converts the value back to floating point.
    • the y = y * ( threehalfs - ( x2 * y * y ) ) line bascially iterates the value over the function again.

    The approximation function gives more precise values the more you iterate the function over the result. In Quake's case, one iteration is "good enough", but if it wasn't for you... then you could add as much iteration as you need.

    This should be faster because it reduces the number of division operations done in naive square rooting down to a simple divide by 2 (actually a * 0.5F multiply operation) and replace it with a few fixed number of multiplication operations instead.

提交回复
热议问题