【问题标题】:Fast inverse square root using fixed point instead of floating point使用定点而不是浮点的快速反平方根
【发布时间】:2021-07-04 13:17:06
【问题描述】:

我正在尝试为定点数实现Fast Inverse Square Root,但我没有得到任何结果。

我试图遵循与文章完全相同的原则,除了不是以浮点格式x = (-1) ^ s * (1 + M) * 2 ^ (E-127) 写入数字,我使用的是x = M * 2 ^ -16 格式,这是一个 32 位定点数16 个小数位和 16 个小数位。

问题是我找不到“魔法常数”的值。根据我的计算,它不存在,但我不是数学家,我认为我做的一切都错了。

为了解决Y = 1 / sqrt(x),我使用了以下推理(不知道是否正确)。

在原始代码中,牛顿的近似值 Y0 由下式给出:

i = 0x5f3759df - (i >> 1);

这意味着我们将因此得到一个浮点数:

y0 = (1 + R2 - M / 2) * 2 ^ (R1 - E / 2);

这是因为 >> 运算将指数和尾数除以 2,然后我们将数字减为整数。

按照文章中显示的步骤,我将x的格式设置为:

x = M * 2 ^ -16

为了尝试执行相同的逻辑,我尝试将 Y0 定义为:

Y0 = (R2 - M / 2) * 2 ^ (R1 - (-16/2));

我正在尝试找到一个数字,它可以最大程度地减少以下给出的错误:

error = (Y - Y0) / Y

无论 R1 的值如何,我都可以进行移位运算来校正最终结果的指数值,从而在固定点获得正确的结果。

我哪里错了?

【问题讨论】:

  • 如果是数学问题,也许这个问题属于数学交换。
  • @ChristianGibbons:当然不是; “Fast Inverse Square Root”使用 IEEE-754 binary32 浮点表示的细节以及浮点运算的特性,而使算法适应定点运算的任务是一个软件工程问题。

标签: c++ c math approximation fixed-point


【解决方案1】:

做不到。

快速逆 sqrt 是由于浮点表示,它已经将数字分成了 2 的幂(指数)和重要的。

可以做到的。

使用与浮点相同的技巧,可以将定点转换为 2^exp * x。给定uint32_t auint8_t exp = bias- builtin_count_leading_zeros(a)uint32_t b = a << exp,常量(和a 的域)经过精心挑选,不会出现下溢或上溢。

因此,您实际上将拥有一个自定义浮点表示,它是为此特定目的量身定制的,至少省略符号位并为指数提供尽可能多的位数,也可能是 8。

【讨论】:

  • 我看到了一个使用相同原理的技术,但是我将来会在 FPGA 中实现这个算法,“builtin_count_leading_zeros”不是一件好事。这将涉及“优先编码器”,据我所知,它将限制我可以在电路上使用的时钟速度。这个算法是不是走错路了?
  • @vincente cesar 最好在问题中提及这一点。我们不知道您的 FPGA 的细节。您可以尝试逐位算法,无论是恢复还是非恢复变体,并可能将其流水线化。如果您有一个计数前导零电路、乘法器和一些 ROM 空间,您可以尝试我在 this answer 中展示的基于牛顿拉夫森的算法
  • 这里讨论了John Carmack's, Fast Inverse Square Root 中使用精心挑选的常量的方法。美妙之处在于解决方案通常在 3 次迭代内收敛,使其在所选精度内非常有效。
  • 在 FPGA 中,我可能会通过一次左移 16、8、4、2、1 位来归一化该值,每次迭代时获得一位作为指数。它可能不会限制时钟速度,但会增加延迟。
  • @AkiSuihkonen 我正在尝试研究链接上的算法。是否可以调整它来计算数字的倒数?我还在努力理解。我正在阅读尽可能多的解决方案,它的算法在计算平方根的倒数和倒数方面看起来都是最好的。我正在使用 FPGA Spartan 6 xc6slx16。
猜你喜欢
  • 2012-03-03
  • 1970-01-01
  • 1970-01-01
  • 2011-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-15
  • 1970-01-01
相关资源
最近更新 更多