这个sqrt近似内联汇编函数如何工作?

这个sqrt近似内联汇编函数如何工作?,第1张

概述通过阅读3D游戏编程大师的技巧,我遇到了这种用内联汇编编写的排序函数: inline float FastSqrt(float Value){ float Result; _asm { mov eax, Value sub eax, 0x3F800000 sar eax, 1 add eax, 0x3F80 通过阅读3D游戏编程大师的技巧,我遇到了这种用内联汇编编写的排序函数:

inline float FastSqrt(float Value){    float Result;    _asm    {        mov eax,Value        sub eax,0x3F800000        sar eax,1        add eax,0x3F800000        mov Result,eax    }    return(Result);}

它是实际平方根的近似值,但精度足以满足我的需要.

这实际上是如何工作的?这个神奇的0x3F800000值是多少?我们如何通过减法,旋转和添加来实现平方根?

以下是它在C/C++代码中的外观:

inline float FastSqrt_C(float Value){    float Result;    long Magic = *((long *)&Value);    Magic -= 0x3F800000;    Magic >>= 1;    Magic += 0x3F800000;    Result = *((float *)&Magic);    return(Result);}
解决方法 很多人都指出0x3f800000是1.0的代表.虽然这是事实,但它与计算的工作方式无关.要理解它,您需要知道如何存储非负浮点数. f =(1m)* 2 ^ x,0 <= m <1. 1是m,尾数是m,x是指数.还要注意x存储有偏差,所以二进制文件实际上是x 127. 32位值由符号位(在我们的例子中为零)后跟8位指数存储x 127而最后由23位尾数,m. (见 wikipedia article).

应用一些基本的数学,

sqrt(f) = sqrt((1+m)*2^x)        = sqrt(1+m)*sqrt(2^x)        = sqrt(1+m)*2^(x/2)

所以,作为一个粗略的近似,我们需要将指数减半但由于偏差我们不能只做x / 2我们需要(x-127)/ 2 127.这127个移位到适当的位位置是神奇的0x3f800000 .

使用右移一位来实现2的除法.由于它在整个浮子上运行,因此它对尾数也有副作用.

首先,假设原始指数是偶数.然后,移出的最低有效位为零.因此,尾数也减半,所以我们最终得到的结果是:sqrt(f)=(1 m / 2)* 2 ^(x / 2).我们得到了指数正确,但尾数是(1 m / 2)而不是sqrt(1 m).这个的最大相对误差是(1.5 – sqrt(2))/ sqrt(2)~6%,如果m几乎为1意味着f接近但小于2的奇数幂,则会出现这种情况.例如f = 7.99 .该公式给出了大约2.998而不是2.827,其确实具有6%的误差.

现在,如果指数是奇数,则最低有效位将为1,当转移到尾数时,这将导致增加一半.因此,我们得到sqrt(f)=(1.5 m / 2)* 2 ^((x-1)/ 2).这个的最大误差实际上是当m = 0时,那将是(1.5 / sqrt(2)-sqrt(1))/ sqrt(1),这也是6%左右.对于从上方接近奇数幂2的数字,会发生这种情况.

如果输入值恰好接近2的奇数幂,则两种情况相结合意味着最差的不准确度约为6%.对于偶数2的幂,结果是准确的.

总结

以上是内存溢出为你收集整理的这个sqrt近似内联汇编函数如何工作?全部内容,希望文章能够帮你解决这个sqrt近似内联汇编函数如何工作?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/1030211.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存