如何解决Lua:代码优化矢量长度计算
| 我在游戏中有一个脚本,该脚本具有每秒被调用的功能。玩家对象与其他游戏对象之间的距离在那里每秒计算一次。问题在于,一秒钟内最多可能有800个函数调用(最多40个播放器* 2个主要对象(1个最多10个子对象))。我必须优化此功能以减少处理。这是我当前的功能:local square = math.sqrt;
local getDistance = function(a,b)
local x,y,z = a.x-b.x,a.y-b.y,a.z-b.z;
return square(x*x+y*y+z*z);
end;
-- for example followed by: for i = 800,1 do getDistance(posA,posB); end
我发现,math.sqrt函数的本地化通过
local square = math.sqrt;
是关于速度和代码的重大优化
x*x+y*y+z*z
比以下代码更快:
x^2+y^2+z^2
我不知道x,y和z的本地化是否比使用类方法“ ..”更好,所以也许square(a.x*b.x+a.y*b.y+a.z*b.z)
比代码local x,a.z-b.z;
square(x*x+y*y+z*z);
好
数学中是否有更好的方法来计算向量长度,或者Lua中是否有更多性能提示?
解决方法
您应该阅读Roberto Ierusalimschy的Lua Performance Tips(Roberto是Lua的首席设计师)。它涉及您所要求的一些小优化(例如,本地化库函数并用多倍等价物替换指数)。最重要的是,它传达了工程学中最重要且最容易被忽略的想法之一:有时最好的解决方案涉及更改问题。您不会通过减少计算所需的CPU周期数来解决3000万次计算泄漏。
在距离计算的特定情况下,您会发现最好使原始计算返回表示平方距离的中间和,并允许用例仅在需要时才调用毕达哥拉斯的最终步骤,通常不需要(例如,您不需要执行平方根即可比较两个平方长度中的哪个更长)。
不过,在进行任何有关优化的讨论之前,确实应该做到这一点:不要担心不是问题的问题。与其检查代码中是否存在任何可能的问题,不如直接解决最大的问题-如果在最明显的问题上性能超过了缺少的功能,错误和/或UX缺点,那么微效率低下几乎是不可能的。已经累积到超过单个瓶颈声明的程度。
或者,如被引文章的开头所述:
在Lua中,就像在任何其他编程语言中一样,我们应始终遵循两者
程序优化准则:
规则1:不要这样做。
规则2:不要这样做。 (仅适用于专家)
, 老实说,我怀疑这些微优化真的对任何事情都没有帮助。
您应该专注于算法,例如通过修剪摆脱一些距离计算,停止计算值的平方根以进行比较(提示:如果
a^2
<b^2
和a
> 0和b
> 0,则a
<b
)等
, 您的“强力”方法无法很好地扩展。
我的意思是,系统中包含的每个新对象/播放器都会大大增加操作次数:
+---------+--------------+
| objects | calculations |
+---------+--------------+
| 40 | 1600 |
| 45 | 2025 |
| 50 | 2500 |
| 55 | 3025 |
| 60 | 3600 |
... ... ...
| 100 | 10000 |
+---------+--------------+
如果您继续比较“一切皆有”,您的算法将以一种古怪的方式开始占用越来越多的CPU周期。
优化代码的最佳选择不是进行数学运算“微调”,也不是使用局部变量代替引用。
真正提高您的算法效率的是消除不需要的计算。
如果您已经计算了Player2和Player1之间的距离,那么最明显的例子就是不计算Player1和Player2之间的距离。这种简单的优化应将您的时间减少一半。
另一个非常常见的实现方式是将空间划分为“区域”。当两个对象位于同一区域时,通常可以计算它们之间的间隔。当它们位于不同的区域时,可以使用近似值。划分空间的理想方式取决于您的环境。例如,将空间划分为网格,对于不同正方形的玩家,请使用您预先计算的正方形中心之间的距离)。
编程中有一个完整的分支处理该问题。称为空间分区。看一下:
http://en.wikipedia.org/wiki/Space_partitioning
,认真吗
运行800次这些计算所花费的时间不应超过0.001秒-即使在手机上使用Lua进行计算。
您是否进行了分析以查看它是否真的使您放慢了脚步?您是否用\“ return(0)\”替换了该功能,以验证性能是否提高(是的,该功能将丢失)。
您确定它每秒运行一次,而不是每毫秒运行一次吗?
自1987年以来,我还没有看到在1秒钟内运行800个简单事物的问题。
, 如果要计算正数a
的sqrt,则采取递归序列
x_0 = a
x_n+1 = 1/2 * (x_n + a / x_n)
x_n
和n -> infinity
移至sqrt(a)
。前几次迭代应该足够快。
顺便说一句!也许您会尝试使用以下公式计算标准输入向量的长度。
local getDistance = function(a,b)
local x,y,z = a.x-b.x,a.y-b.y,a.z-b.z;
return x+y+z;
end;
它更容易计算,并且在某些情况下(例如,如果需要距离来确定两个物体是否靠近),它可能就足够了。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。