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.
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.
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].
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.
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) { ... }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With