首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用InvSqrt编写Quake的快速InvSqrt()函数有可能吗?

用InvSqrt编写Quake的快速InvSqrt()函数有可能吗?
EN

Stack Overflow用户
提问于 2008-11-06 14:25:12
回答 4查看 10.2K关注 0票数 32

这只是为了满足我自己的好奇心。

是否实现了这一目标:

代码语言:javascript
复制
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代码解决了这个问题。工会的想法很有趣。我会测试并发布我的结果。

编辑:正如预期的那样,不安全的方法是最快的,其次是使用一个联合(函数内部),其次是BitConverter。这些函数被执行了10000000次,I使用System.Diagnostics.Stopwatch类来计时。计算结果显示在括号内。

代码语言:javascript
复制
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))。

代码语言:javascript
复制
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()也更准确。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2008-11-06 14:40:59

您应该能够使用StructLayout和FieldOffset属性来伪造一个普通旧数据的联合,比如floats和ints。

代码语言:javascript
复制
[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就很容易了。

票数 13
EN

Stack Overflow用户

发布于 2008-11-06 14:39:46

如果要避免不安全的代码,请使用BitConverter

代码语言:javascript
复制
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;
}

上面的代码使用了.NET Core2.0中引入的新方法。对于.NET框架,必须返回以下内容(执行分配):

代码语言:javascript
复制
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;
}

否则,C#代码与您提供的C代码完全相同,只需将该方法标记为不安全:

代码语言:javascript
复制
unsafe float InvSqrt(float x) { ... }
票数 11
EN

Stack Overflow用户

发布于 2008-11-06 14:45:55

绝对有可能在不安全的情况下。请注意,尽管在地震3源代码中使用了常数0x5f3759df,但数值研究表明表示,对于牛顿近似,常数0x5f375a86实际上得到了更好的结果。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/268853

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档