我正在阅读一本关于2D游戏编程的书,我正在通过3x3矩阵类进行线性变换。作者编写了一种方法,用于将两个3x3矩阵相乘如下。
public Matrix3x3f mul(Matrix3x3f m1)
{
return new Matrix3x3f(new float[][]
{
{
this.m[0][0] * m1.m[0][0] // M[0,0]
+ this.m[0][1] * m1.m[1][0]
+ this.m[0][2] * m1.m[2][0],
this.m[0][0] * m1.m[0][1] // M[0,1]
+ this.m[0][1] * m1.m[1][1]
+ this.m[0][2] * m1.m[2][1],
this.m[0][0] * m1.m[0][2] // M[0,2]
+ this.m[0][1] * m1.m[1][2]
+ this.m[0][2] * m1.m[2][2],
},
{
this.m[1][0] * m1.m[0][0] // M[1,0]
+ this.m[1][1] * m1.m[1][0]
+ this.m[1][2] * m1.m[2][0],
this.m[1][0] * m1.m[0][1] // M[1,1]
+ this.m[1][1] * m1.m[1][1]
+ this.m[1][2] * m1.m[2][1],
this.m[1][0] * m1.m[0][2] // M[1,2]
+ this.m[1][1] * m1.m[1][2]
+ this.m[1][2] * m1.m[2][2],
},
{
this.m[2][0] * m1.m[0][0] // M[2,0]
+ this.m[2][1] * m1.m[1][0]
+ this.m[2][2] * m1.m[2][0],
this.m[2][0] * m1.m[0][1] // M[2,1]
+ this.m[2][1] * m1.m[1][1]
+ this.m[2][2] * m1.m[2][1],
this.m[2][0] * m1.m[0][2] // M[2,2]
+ this.m[2][1] * m1.m[1][2]
+ this.m[2][2] * m1.m[2][2],
},
});
}
如果我个人需要编写一个方法来做同样的事情我会想出一些嵌套循环自动完成所有这些计算,我假设也许作者已经用这种方式编写了它以便人们很少数学背景可以更容易。
这听起来是一个公平的假设,还是这个方法的嵌套循环版本在性能至关重要的循环中大量使用时可能会导致性能问题?
答案 0 :(得分:2)
我认为这是一个性能问题。 如果你使用一个循环,它将使用大量的跳跃命令,因为它需要检查每一次迭代"如果cond goto ___"。您应该阅读Branch Prediction上的这篇文章,并了解计算机体系结构以了解指令如何影响性能,在这种情况下,我认为您可能会发现缓存很有趣。
答案 1 :(得分:1)
从它的外观来看,我认为这是为了清晰起见,而不是为了表现。考虑一下它的Java代码。 return语句中有对象分配。如果性能如此严重以至于无法提供for循环的条件跳转,则结果将被写入可变实例。
答案 2 :(得分:0)
如果硬编码操作与循环处理的操作完全相同,我可以看不出循环效率较低的原因(或者至少不是以相当大的方式)。实际上,大型循环(这里不是这种情况)比硬编码更有效,因为:
我听说,如果循环遍历一个很小的空间,那么对操作进行硬编码可能会更好,但我不认为这样做真的很有趣。
最后,对于乘法矩阵,使用循环或不使用循环不会改变很多事情,可以加速计算的是使用动态编程。我不知道是否值得为小矩阵做这件事,但如果我是你,我会尝试一下。
答案 3 :(得分:0)
这绝对是性能问题。嵌套循环必须递增循环索引并检查循环是否已经结束,这使得它的执行速度变慢。对于计算机图形和CAD / CAM软件,将为每个渲染操作完成3x3或4x4矩阵乘法。因此,矩阵乘法可以轻松完成数百万次。因此,在不使用嵌套循环的情况下实现3x3或4x4矩阵乘法是一种常见的做法,尤其是在没有GPU之类的旧时代。对于超过4行/列的矩阵,仍然使用嵌套循环方法。