《雷神之锤III》求平方根倒数(快速平方根(倒数)算法)之C#版

  在3D图形编程中,经常要求平方根或平方根的倒数,例如:求向量的长度或将向量归一化。C数学函数库中的sqrt具有理想的精度,但对于3D游戏程式来说速度太慢。我们希望能够在保证足够的精度的同时,进一步提高速度。 


Carmack在QUAKE3中使用了下面的算法,它第一次在公众场合出现的时候,几乎震住了所有的人。据说该算法其实并不是Carmack发明的,它真正的作者是Nvidia的Gary Tarolli(未经证实)。 

  

// 
// 计算参数x的平方根的倒数 
// 
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#


unsafe版本

 /// <summary>
        ///  
        ///  Carmack在QUAKE3中使用的计算平方根的函数 
        ///  
        ///             在3D图形编程中,经常要求平方根或平方根的倒数,例如:求向量的长度或将向量归一化。C数学函数库中的sqrt具有理想的精度,但对于3D游戏程式来说速度太慢。我们希望能够在保证足够的精度的同时,进一步提高速度。 

        /// Carmack在QUAKE3中使用了下面的算法,它第一次在公众场合出现的时候,几乎震住了所有的人。据说该算法其实并不是Carmack发明的,它真正的作者是Nvidia的Gary Tarolli(未经证实)。 


        ///  
        ///  计算参数x的平方根的倒数 
        ///  
        /// 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; 
        /// } 
        /// http://www.codemaestro.com/reviews/review00000105.html. 
        /// http://www.beyond3d.com/content/articles/8/
        /// </remarks>
        public static float InverseSqrtFast(float x)
        {
            //return OpenGLTK.MathInverseSqrtFast.InverseSqrtFast(x);
            unsafe
            {
                float xhalf = 0.5f * x;
                int i = *(int*)&x;              // Read bits as integer.
                i = 0x5f375a86 - (i >> 1);      // Make an initial guess for Newton-Raphson approximation
                x = *(float*)&i;                // Convert bits back to float
                x = x * (1.5f - xhalf * x * x); // Perform left single Newton-Raphson step.
                return x;
            }
        }


不带unsafe版本

        ///  
        ///  Carmack在QUAKE3中使用的计算平方根的函数 
        ///  
        ///             在3D图形编程中,经常要求平方根或平方根的倒数,例如:求向量的长度或将向量归一化。C数学函数库中的sqrt具有理想的精度,但对于3D游戏程式来说速度太慢。我们希望能够在保证足够的精度的同时,进一步提高速度。 

        /// Carmack在QUAKE3中使用了下面的算法,它第一次在公众场合出现的时候,几乎震住了所有的人。据说该算法其实并不是Carmack发明的,它真正的作者是Nvidia的Gary Tarolli(未经证实)。 


        ///  
        ///  计算参数x的平方根的倒数 
        ///  
        /// 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# 版 by 大师♂罗莊
        public static float InverseSqrtFast(float x)
        {
            //这个算法依赖于浮点数的内部表示和字节顺序,所以是不具移植性的。如果放到Mac上跑就会挂掉。如果想具备可移植性,还是乖乖用sqrt好了。
            float xhalf = 0.5f * x;
            int i = 0x5f375a86 - (floatToIntBits(x) >> 1); //MagicNumber:0x5f3759df,0x5f375a86
            x = intBitsToFloat(i);
            x = x * (1.5f - xhalf * x * x); //Newton-Raphson Method based on Taylor Series
            return x;
        }

        /// <summary>
        /// java  Float.intBitsToFloat C#版
        /// </summary>
        /// <param name="i"></param>
        /// <returns></returns>
        private static float intBitsToFloat(int i)
        {
            byte[] bytes = BitConverter.GetBytes(i);
            float f = BitConverter.ToSingle(bytes, 0);
            return f;
        }

        public static int changingendianness(float x)
        {
            byte[] bytes = BitConverter.GetBytes(x);
            Array.Reverse(bytes);
            return BitConverter.ToInt32(bytes, 0);

        }

        private static int floatToIntBits(float x)
        {
            byte[] bytes = BitConverter.GetBytes(x);
            int i = BitConverter.ToInt32(bytes, 0);
            return i;
        }

java版

请自行搜索《John Carmark 神奇魔数开方的Java实现 》

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值