就像Z boson recommended一样,我使用的是列主矩阵格式,以避免使用点积。但是,在将矢量与矩阵相乘时,我没有看到避免它的可行方法。矩阵乘法技巧需要有效提取行(或列,如果我们转置产品)。为了将矢量乘以矩阵,我们因此转置:
(b * A)^T = A^T * b^T
A
是一个矩阵,b
一个行向量,在转置后成为一个列向量。它的行只是单个标量,矢量*矩阵产品实现成为(非转置)矩阵A
和b
列的点积的低效实现。有没有办法避免执行这些点产品?我认为可以做到的唯一方法是使用行提取,这对列主矩阵格式来说效率很低。
答案 0 :(得分:1)
这可以从关于此的原始帖子(我的第一篇关于SO)中理解 efficient-4x4-matrix-vector-multiplication-with-sse-horizontal-add-and-dot-prod 。其余讨论适用于4x4矩阵。
这里有两种做矩阵时间向量的方法(v = Mu,其中v和u是列向量)
method 1) v1 = dot(row1, u), v2 = dot(row2, u), v3 = dot(row3, u), v4 = dot(row4, u)
method 2) v = u1*col1 + u2*col2 + u3*col3 + u4*col4.
第一种方法在数学课上更为熟悉,而第二种方法对于SIMD计算机更有效。第二种方法使用矢量化数学(如numpy),例如
u1*col1 = (u1x*col1x, u1y*col1y, u1z*col1z, u1w*col1w).
现在让我们看看向量时间矩阵(v = uM,其中v和u是行向量)
method 1) v1 = dot(col1, u), v2 = dot(col2, u), v3 = dot(col3, u), v4 = dot(col4, u)
method 2) v = u1*row1 + u2*row2 + u3*row3 + u4*row4.
现在列和行的角色已交换,但方法2仍然是在SIMD计算机上使用的有效方法。
要在SIMD计算机上有效地进行矩阵时间矢量,矩阵应按列主要顺序存储。要在SIMD计算机上有效地执行向量时矩阵,矩阵应按行主顺序存储。
据我所知,OpenGL使用列主要排序并执行矩阵时间向量,而DirectX使用行主要排序并执行向量时间矩阵。 如果你有三个矩阵变换,你先按顺序M1,然后是M2,然后用矩阵时间向量的M3,你把它写成
v = M3*M2*M1*u //u and v are column vectors - OpenGL form
使用向量时间矩阵编写
v = u*M1*M2*M3 //u and v are row vectors - DirectX form
就效率而言,两种形式都不比另一种形式更好。这只是一个表示法的问题(当你参加比赛时会造成混乱)。
值得注意的是,对于矩阵*矩阵行主要与列主要存储无关。
如果你想知道为什么垂直SIMD指令比水平指令更快,这是一个应该被问的单独问题但是简而言之,水平指令实际上是串行而不是并行的,并且被分解为几个微指令-ops(具有讽刺意味的是dppd
比dpps
更快的原因)。