/* This is a novel and fast routine for the reciprocal square root of an IEEE float (single precision). It was communicated to me by Mike Morton, and has been analyzed substantially by Chris Lomont. Later (12/1/06) Peter Capek pointed it out to me. See: http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf http://playstation2-linux.com/download/p2lsd/fastrsqrt.pdf. http://www.beyond3d.com/articles/fastinvsqrt/ The author of this has been researched but seems to be lost in history. However, Gary Tarolli worked on it and helped to make it more widely known, while he was at NVIDIA. Gary says it goes back to 1995 or earlier. */ #include #include #include /* ---------------------------- InvSqrt ----------------------------- */ float InvSqrt(float x) { float xhalf = 0.5f*x; int i = *(int *)&x; // View x as an int. i = 0x5f3759df - (i >> 1); // Initial guess. x = *(float *)&i; // View initial guess as float. x = x*(1.5f - xhalf*x*x); // Newton step. return x; } /* Notes: For more accuracy, repeat the Newton step (just duplicate the line). The routine always gets the result too low. According to Chris Lomont, the relative error is at most -0.00175228. Therefore, to cut its relative error in half, making it approximately plus or minus 0.000876, change the 1.5f in the Newton step to 1.500876f. Chris says that changing the hex constant to 0x5f375a86 reduces the maximum relative error slightly, to 0.00175124. However, using that value seems to usually give a slightly larger relative error. The routine can be adapted to IEEE double precision. */ /* ------------------------------ main ------------------------------ */ int main(int argc, char *argv[]) { float x = (float)atof(argv[1]); float yt = (float)(1.0/sqrt(x)); float ya = InvSqrt(x); printf("x = %f\ntrue recip sqrt = %f, approx = %f, rel error = %f\n", x, yt, ya, (ya - yt)/yt); return 0; }