【问题标题】:Estimating the square root估计平方根
【发布时间】:2010-09-16 00:51:45
【问题描述】:

我正在编写一个 iPhone 应用程序,它需要每 1/30 秒计算大约 2000 次数字的平方根。 sqrt() 在计算机上运行良好,但在 iPhone 或 iPad 上帧速率下降到 10 FPS 左右,我已经优化了其余代码。我听说通过估计平方根可以大大加快速度,但我找不到任何代码来做到这一点。我只需要一到两位小数的精度。任何有关如何执行此操作或其他加快速度的方法的建议将不胜感激。

谢谢!

【问题讨论】:

  • 维基百科有一个快速查找的算法描述得很好;你在找什么?
  • 您确定需要计算平方根吗?通常在游戏等的毕达哥拉斯类型计算中,sqrt 可以被魔法消除。你是做什么用的?
  • 或者,如果你不能把它变魔术,你可以使用查找表吗?
  • 了解它的用途以及您将使用的值的范围非常有帮助。例如,如果它真的是 1/sqrt(x) 你想要有专门的方法。如果是 sqrt(1-x*x),我发现 maclaurin 系列对于 |x| 来说非常快速和简单小于 0.8。最好的方法取决于你的使用。
  • 感谢所有出色的答案!下面的答案是我为什么喜欢 StackOverflow 的一个很好的例子——每个人都非常乐于助人,并且知识渊博,他们可以用易于理解的方式进行解释。谢谢大家!

标签: objective-c iphone sqrt square-root


【解决方案1】:

除非您确实需要平方根,否则请比较平方值而不是原始值和平方根。

如果您只需要比较,平方比取平方根要快得多(也更准确)。这是大多数游戏的做法。

【讨论】:

  • 你会如何最快地比较它们?您会使用预先计算的平方值数组,然后使用二进制搜索来找到最接近的吗?
  • 他的意思是:比如你只是比较两个向量的长度。您不需要使用欧几里得范数(需要 sqrt)来执行此操作,您可以使用平方范数。对于许多其他情况,如果您对绝对值不感兴趣,您可以在平方空间中工作。
【解决方案2】:

您知道要求平方根的值的范围吗?假设您的值范围从 0 到 10。然后您可以预先计算一个数组:

sqrt_val[0] = 0;
sqrt_val[1] = 1;
sqrt_val[2] = // the sqrt of 2
...
sqrt_val[10] = // the sqrt of 10

然后在运行时,您获取您想要的 sqrt 的数字,将其转换为整数(例如 3.123 变为 3)并将其用作索引 (3) 以查找预先计算的值。

当然,如果您想要更精细的分辨率,您可以增加数组中的项目数。

【讨论】:

  • 浮点到整数的转换也不是特别便宜。
  • 如果这是个问题,请尝试使用整数作为坐标并将所有计算作为整数。
【解决方案3】:

首先,您确定平方根实际上是瓶颈吗?你有简介吗?每 1/30 秒 2000 平方根实际上并不是那么多,即使在手机上也是如此。 ARM 文档引用单精度平方根 33 个周期和双精度 60 个周期;一个 600mHz 处理器每秒可以处理 1000 万 个平方根(如果指令是流水线的,则更多)。

如果您进行了分析,并且平方根确实是瓶颈,您将需要使用 NEON vrsqrte.f32 指令。该指令非常快,并且可以同时为您提供四个浮点数的近似倒数平方根。然后,您可以使用vmul.f32 指令来获得近似的平方根(尽管对于许多用途来说,倒数比平方根本身更有用)。

【讨论】:

    【解决方案4】:

    您希望自己的估计有多准确?如果您知道您希望自己的估算值与实际 sqrt 有多接近,Newton's Method 就是您的朋友。

    你知道传递给 sqrt 的值的范围吗?如果是这样,您可以制作一个在启动时预先计算的查找表(甚至在启动时从磁盘读取,具体取决于结果更快)。在表中找到与您的输入最接近的值,然后您就可以得到估算值。

    【讨论】:

    • 或者特别是牛顿法 + 预计算,很有可能。
    【解决方案5】:

    也许这是给你的:
    Fast inverse square root
    如果此方法不能提供您需要的准确度,还有许多其他迭代方法,您可以在速度和准确度之间选择或多或少的精确度:
    Methods of computing square roots

    【讨论】:

    • 另外值得注意的是 sqrt(x) = x*(1/sqrt(x)) 和 1/x = (1/sqrt(x))**2 所以有一个快速倒数平方根实际上比它最初看起来更有用。事实上,如果我必须将有限的硬件专用于数学,我会选择它而不是除法:-)
    【解决方案6】:

    您可以在 iPhone 上进行的最简单的更改是使用 sqrtf() 而不是 sqrt()。单精度浮点数学比双精度快得多,尤其是在 3GS 老式和更新的设备上。

    【讨论】:

      【解决方案7】:

      如果您需要平方根来计算毕达哥拉斯三角形 (sqrt(x*x + y*y)),并且 x 和 y 都是非负数,那么一个非常快速的近似是

      max(x,y) + min(x,y)*0.333
      

      最大误差为 5.7%。不过要注意 min() 和 max() 中的分支预测错误。

      【讨论】:

        【解决方案8】:
        【解决方案9】:

        如果您有一个“正常”的正浮点数或双精度,而不是整数,并且想要使用查表方法,您可以进行两次单独的查表,一次用于指数(重新偏置),并且一位为尾数的几位(移位和掩码位域提取),然后将两个查表结果相乘。

        【讨论】:

          猜你喜欢
          • 2021-02-22
          • 2021-08-03
          • 2017-04-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多