Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to write Quake's fast InvSqrt() function in C#?

Tags:

c#

This is just to satisfy my own curiosity.

Is there an implementation of this:

float InvSqrt (float x) {    float xhalf = 0.5f*x;    int i = *(int*)&x;    i = 0x5f3759df - (i>>1);    x = *(float*)&i;    x = x*(1.5f - xhalf*x*x);    return x; } 

in C#? If it exists, post the code.

I guess I should have mentioned I was looking for a "safe" implementation... Either way, the BitConverter code solves the problem. The union idea is interesting. I'll test it and post my results.

Edit: As expected, the unsafe method is the quickest, followed by using a union (inside the function), followed by the BitConverter. The functions were executed 10000000 times, and the I used the System.Diagnostics.Stopwatch class for timing. The results of the calculations are show in brackets.

Input: 79.67 BitConverter Method: 00:00:01.2809018 (0.1120187) Union Method: 00:00:00.6838758 (0.1120187) Unsafe Method: 00:00:00.3376401 (0.1120187) 

For completeness, I tested the built-in Math.Pow method, and the "naive" method (1/Sqrt(x)).

Math.Pow(x, -0.5): 00:00:01.7133228 (0.112034710535584) 1 / Math.Sqrt(x): 00:00:00.3757084 (0.1120347) 

The difference between 1 / Math.Sqrt() is so small that I don't think one needs to resort to the Unsafe Fast InvSqrt() method in C# (or any other unsafe method). Unless one really needs to squeeze out that last bit of juice from the CPU... 1/Math.Sqrt() is also much more accurate.

like image 866
ilitirit Avatar asked Nov 06 '08 14:11

ilitirit


People also ask

Who wrote the fast inverse square root?

Treating the bits again as a floating-point number, it runs one iteration of Newton's method, yielding a more precise approximation. The algorithm was originally attributed to John Carmack, but an investigation showed that the code had deeper roots in the hardware and software side of computer graphics.

Is fast inverse square root?

Fast Inverse Square Root (Fast InvSqrt) is an algorithm that quickly estimates the inverse of the square root of a float variable. The algorithm appeared first in Quake III Arena first-person shooter game source code [1].


2 Answers

You should be able to use the StructLayout and FieldOffset attributes to fake a union for plain old data like floats and ints.

[StructLayout(LayoutKind.Explicit, Size=4)] private struct IntFloat {     [FieldOffset(0)]     public float floatValue;      [FieldOffset(0)]     public int intValue;      // redundant assignment to avoid any complaints about uninitialized members     IntFloat(int x) {         floatValue = 0;         intValue = x;     }      IntFloat(float x) {          intValue = 0;         floatValue = x;     }      public static explicit operator float (IntFloat x) {         return x.floatValue;     }      public static explicit operator int (IntFloat x) {          return x.intValue;     }      public static explicit operator IntFloat (int i) {         return new IntFloat(i);     }     public static explicit operator IntFloat (float f) {          return new IntFloat(f);     } } 

Then translating InvSqrt is easy.

like image 131
Edward Kmett Avatar answered Sep 22 '22 19:09

Edward Kmett


Use BitConverter if you want to avoid unsafe code.

float InvSqrt(float x) {     float xhalf = 0.5f * x;     int i = BitConverter.SingleToInt32Bits(x);     i = 0x5f3759df - (i >> 1);     x = BitConverter.Int32BitsToSingle(i);     x = x * (1.5f - xhalf * x * x);     return x; } 

The code above uses new methods introduced in .NET Core 2.0. For .NET Framework, you have to fall back to the following (which performs allocations):

float InvSqrt(float x) {     float xhalf = 0.5f * x;     int i = BitConverter.ToInt32(BitConverter.GetBytes(x), 0);     i = 0x5f3759df - (i >> 1);     x = BitConverter.ToSingle(BitConverter.GetBytes(i), 0);     x = x * (1.5f - xhalf * x * x);     return x; } 

Otherwise, the C# code is exactly the same as the C code you gave, except that the method needs to be marked as unsafe:

unsafe float InvSqrt(float x) { ... } 
like image 42
Bradley Grainger Avatar answered Sep 20 '22 19:09

Bradley Grainger