我正在编写一个 iPhone 应用程序,它需要每 1/30 秒计算大约 2000 次数字的平方根。sqrt() 在计算机上运行良好,但在 iPhone 或 iPad 上帧速率下降到 10 FPS 左右,我已经优化了其余代码。我听说可以通过估计平方根来显着加快速度,但我找不到任何代码来做到这一点。我只需要一到两位小数的精度。任何有关如何执行此操作或其他加快速度的方法的建议将不胜感激。
谢谢!
我正在编写一个 iPhone 应用程序,它需要每 1/30 秒计算大约 2000 次数字的平方根。sqrt() 在计算机上运行良好,但在 iPhone 或 iPad 上帧速率下降到 10 FPS 左右,我已经优化了其余代码。我听说可以通过估计平方根来显着加快速度,但我找不到任何代码来做到这一点。我只需要一到两位小数的精度。任何有关如何执行此操作或其他加快速度的方法的建议将不胜感激。
谢谢!
除非您确实需要平方根,否则请比较平方值而不是原始值和平方根。
如果您只需要比较,平方比取平方根要快得多(也更准确)。这是大多数游戏的做法。
你知道你试图找到平方根的值的范围吗?假设您的值范围从 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) 以查找预先计算的值。
当然,如果您想要更精细的分辨率,您可以增加数组中的项目数。
首先,您确定平方根实际上是瓶颈吗?你有简介吗?每 1/30 秒 2000 平方根实际上并不是那么多,即使在手机上也是如此。ARM 文档引用单精度平方根 33 个周期和双精度 60 个周期;一个 600mHz 的处理器每秒可以处理1000 万平方根(如果指令是流水线的,则更多)。
如果您进行了分析,并且平方根确实是瓶颈,您将需要使用 NEONvrsqrte.f32
指令。该指令非常快,并且可以同时为您提供四个浮点数的近似倒数平方根。然后,您可以使用该vmul.f32
指令获得近似平方根(尽管对于许多用途而言,倒数比平方根本身更有用)。
你希望你的估计有多准确?如果您知道您希望您的估计与实际 sqrt 有多接近,那么牛顿法就是您的朋友。
你知道传递给 sqrt 的值的范围吗?如果是这样,您可以制作一个在启动时预先计算的查找表(甚至在启动时从磁盘读取,具体取决于结果更快)。在表格中找到最接近您输入的值,然后您就可以得到估计值。
您可以在 iPhone 上进行的最简单更改是使用 sqrtf() 而不是 sqrt()。单精度浮点数学比双精度快得多,尤其是在 3GS 老式和更新的设备上。
如果您需要平方根来计算毕达哥拉斯三角形 (sqrt(x*x + y*y)),并且 x 和 y 都是非负数,那么一个非常快速的近似值是
max(x,y) + min(x,y)*0.333
最大误差为 5.7%。不过要注意 min() 和 max() 中的分支预测错误。
快速的谷歌搜索会出现各种链接。
如果您有一个“正常”的正浮点数或双精度数,而不是整数,并且想要使用表查找方法,您可以进行两次单独的表查找,一次用于指数(重新偏置),一次用于尾数的几位(移位和掩码位域提取),然后将两个表查找结果相乘。