这只是为了满足我自己的好奇心.
是否有这样的实现:
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; }
在C#?如果存在,请发布代码.
我想我应该提到我正在寻找一个"安全"的实现......无论哪种方式,BitConverter代码解决了这个问题.工会的想法很有趣.我会测试它并发布我的结果.
编辑:正如预期的那样,不安全的方法是最快的,然后使用union(在函数内),然后是BitConverter.这些函数执行了10000000次,我使用System.Diagnostics.Stopwatch类进行计时.计算结果显示在括号中.
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)
为了完整性,我测试了内置的Math.Pow方法和"天真"方法(1/Sqrt(x)).
Math.Pow(x, -0.5): 00:00:01.7133228 (0.112034710535584) 1 / Math.Sqrt(x): 00:00:00.3757084 (0.1120347)
1/Math.Sqrt()之间的差异是如此之小,以至于我认为不需要在C#(或任何其他不安全的方法)中使用不安全的快速InvSqrt()方法.除非真的需要从CPU中挤出最后一点果汁...... 1/Math.Sqrt()也更准确.
您应该能够使用StructLayout和FieldOffset属性伪造一个简单旧数据(如浮点数和整数)的并集.
[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); } }
然后翻译InvSqrt很容易.
如果要避免不安全的代码,请使用BitConverter.
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; }
否则,C#代码与您给出的C代码完全相同,只是该方法需要标记为不安全:
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; }
绝对可以在不安全的模式下.请注意,即使在Quake 3源代码中使用常量0x5f3759df
,数值研究表明该常数0x5f375a86
实际上会产生更好的牛顿近似结果.