2013-04-04 149 views
4

我正在寻找最有效的方式来为C#中的3x3旋转和4x4变换矩阵执行matrix * matrixmatrix * vector操作。快速旋转/变换矩阵乘法

我目前将我的矩阵存储在多维数组中(new double[3,3]new double[4,4])。我并不完全不利于改变,但如果可能的话,我想保留语法。我目前使用3个标准嵌套for循环的乘法工作正常,但可能是一个瓶颈。

我的想法至今:

  • 优化算法,如施特拉森不是这些尺寸
  • 并行化并没有在一个4x4的乘法的级别太大的意义要么实用;在更高层次上做得更好。
  • 由于边界检查效率较低,多维数组在C#中速度较慢(分别为?),但这可以通过不安全的指针算法来克服。 (我不知道这个信息是如何当前)
  • 旋转矩阵是对称的,可能有一种方法来利用它?
  • 可以通过使用缓存局部性来获得最大的收益,确保一起访问内存中紧密相邻的值;但我不确定如何做到这一点。

因此,在我使用不安全,固定和3 for for循环将自己的解决方案拼凑在一起之前,是否有针对此标准问题的经过测试和优化的解决方案?

还是有其他优化,我忽略了?

+1

为什么不使用现有的Microsoft.Xna.Framework.Matrix结构? (http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.matrix.aspx)它也有一个Multiply方法:http://msdn.microsoft。com/en-us/library/bb198134.aspx – pascalhein 2013-04-04 17:35:37

+0

好点,之前没有注意到!检查一下,它会涉及一些相当大的语法变化,并且从double切换到float,以及向xna框架添加依赖项,但这绝对是需要考虑的事情。 – HugoRune 2013-04-04 17:40:20

+0

相应的向量将是Vector2/Vector3/Vector4,您可以使用Vector3.Transform()作为矩阵向量(http://msdn.microsoft.com/en-us/) library/microsoft.xna.framework.vector3.transform.aspx) – pascalhein 2013-04-04 17:41:29

回答

3

这是我使用的,它的工作速度惊人的快。

public struct Matrix3 
{ 
    public readonly double a11, a12, a13; 
    public readonly double a21, a22, a23; 
    public readonly double a31, a32, a33; 
    ... 
    public vec3 Multiply(vec3 rhs) 
    { 
     // y= A*x 
     // fill vector by element 
     return new vec3(
      (a11*rhs.X+a12*rhs.Y+a13*rhs.Z), 
      (a21*rhs.X+a22*rhs.Y+a23*rhs.Z), 
      (a31*rhs.X+a32*rhs.Y+a33*rhs.Z)); 
    } 

    public mat3 Multiply(mat3 rhs) 
    { 
     // Y = A*X 
     // fill matrix by row 
     return new mat3(
      (a11*rhs.a11+a12*rhs.a21+a13*rhs.a31), 
      (a11*rhs.a12+a12*rhs.a22+a13*rhs.a32), 
      (a11*rhs.a13+a12*rhs.a23+a13*rhs.a33), 

      (a21*rhs.a11+a22*rhs.a21+a23*rhs.a31), 
      (a21*rhs.a12+a22*rhs.a22+a23*rhs.a32), 
      (a21*rhs.a13+a22*rhs.a23+a23*rhs.a33), 

      (a31*rhs.a11+a32*rhs.a21+a33*rhs.a31), 
      (a31*rhs.a12+a32*rhs.a22+a33*rhs.a32), 
      (a31*rhs.a13+a32*rhs.a23+a33*rhs.a33)); 
    } 
} 

其中vec3mat3是别名我自己Vector3Matrix3结构存储的元素领域。类似的4个元素结构。我也编码它反转像这样:

public double Determinant() 
    { 
     return a11*(a22*a33-a23*a32) 
      +a12*(a23*a31-a21*a33) 
      +a13*(a21*a32-a22*a31); 
    } 
    /// <summary> 
    /// Solves the system of equations this*x=rhs for x 
    /// </summary> 
    public vec3 Solve(vec3 rhs) 
    { 
     double D=Determinant(); 
     double ID=1/D; 
     return new vec3(
      (((a22*a33-a23*a32)*rhs.X+(a13*a32-a12*a33)*rhs.Y+(a12*a23-a13*a22)*rhs.Z)*ID), 
      -(((a21*a33-a23*a31)*rhs.X+(a13*a31-a11*a33)*rhs.Y+(a11*a23-a13*a21)*rhs.Z)*ID), 
      (((a21*a32-a22*a31)*rhs.X+(a12*a31-a11*a32)*rhs.Y+(a11*a22-a12*a21)*rhs.Z)*ID)); 
    } 
    /// <summary> 
    /// Solves the system of equations this*X = rhs for X 
    /// </summary> 
    public mat3 Solve(mat3 rhs) 
    { 
     double D=Determinant(); 
     double ID=1/D; 
     return new mat3(
      (((a22*a33-a23*a32)*rhs.a11+(a13*a32-a12*a33)*rhs.a21+(a12*a23-a13*a22)*rhs.a31)*ID), 
      (((a22*a33-a23*a32)*rhs.a12+(a13*a32-a12*a33)*rhs.a22+(a12*a23-a13*a22)*rhs.a32)*ID), 
      (((a22*a33-a23*a32)*rhs.a13+(a13*a32-a12*a33)*rhs.a23+(a12*a23-a13*a22)*rhs.a33)*ID), 

      -(((a21*a33-a23*a31)*rhs.a11+(a13*a31-a11*a33)*rhs.a21+(a11*a23-a13*a21)*rhs.a31)*ID), 
      -(((a21*a33-a23*a31)*rhs.a12+(a13*a31-a11*a33)*rhs.a22+(a11*a23-a13*a21)*rhs.a32)*ID), 
      -(((a21*a33-a23*a31)*rhs.a13+(a13*a31-a11*a33)*rhs.a23+(a11*a23-a13*a21)*rhs.a33)*ID), 

      (((a21*a32-a22*a31)*rhs.a11+(a12*a31-a11*a32)*rhs.a21+(a11*a22-a12*a21)*rhs.a31)*ID), 
      (((a21*a32-a22*a31)*rhs.a12+(a12*a31-a11*a32)*rhs.a22+(a11*a22-a12*a21)*rhs.a32)*ID), 
      (((a21*a32-a22*a31)*rhs.a13+(a12*a31-a11*a32)*rhs.a23+(a11*a22-a12*a21)*rhs.a33)*ID)); 
    } 
1

如果你想要它在微软的C#性能,我会;

  • 展开循环。不要使用循环,而是全部写出 这对于这些较小的固定大小乘法是可行的。
  • 将第一建议后,尝试不安全的修正版本 (这仍然事项许多快速数组访问)

对于单声道,在Mono.SIMD库可能是值得一试。

对于使用GPU的并行性来说,如果您可以同时卸载 其中的很多这种情况,那么这将非常合适。对于C#我会考虑http://www.hybriddsp.com/Products/CUDAfyNET.aspx,但可能会有其他人。我还没有从C#做任何GPU的东西,但这是我的出发点。

+1

并行化3x3和4x4矩阵运算并不值得。只有1000或更多的元素可能会有一些好处(从我的经验)。实践中不安全的固定结构对于此应用程序来说也不值得。 – ja72 2013-04-08 13:21:06

+1

@ ja72因此,我说'如果你可以卸载许多这些'。在这种情况下,您可以并行执行数百个4x4。我并没有说你应该将每次操作并行4次4次。 – IvoTops 2013-04-08 17:45:17