为什么在类函数中乘以两个Eigen Matrix4d对象会产生不正确的结果?

时间:2018-01-17 04:52:34

标签: c++ eigen

我正在使用Eigen库作为大型项目的一部分,并且我遇到了两个Matrix4d对象相乘会产生数学上不正确的结果的情况。

但是,只有当矩阵用作类变量 AND 时才会产生不正确的结果仅在较大程序的一部分时。< / p>

相关代码简化为基本部分:

class MatrixContainer
{
  public:
    Eigen::Matrix4d m1;
    Eigen::Matrix4d m2;
};

class DummyClass
{
  public:
    MatrixContainer matrices;

    void multiplyMatrices()
    {
      print4x4Matrix("C1 = AB =", matrices.m1*matrices.m2);
    }
};

void print4x4MatrixEnhanced (string inputs, const Eigen::Matrix4d & matrix)
{
    string blanks(inputs.length(), ' ');

    printf ("\n");
    cout << blanks; printf (" | %6.3f %6.3f %6.3f %6.3f | \n", matrix (0, 0), matrix (0, 1), matrix (0, 2), matrix (0, 3));
    cout << inputs; printf (" | %6.3f %6.3f %6.3f %6.3f | \n", matrix (1, 0), matrix (1, 1), matrix (1, 2), matrix (1, 3));
    cout << blanks; printf (" | %6.3f %6.3f %6.3f %6.3f | \n", matrix (2, 0), matrix (2, 1), matrix (2, 2), matrix (2, 3));
    cout << blanks; printf (" |  0      0      0      1     | \n");
    printf ("\n");
}

int main()
{
  Eigen::Matrix4d tmp_m1;
  Eigen::Matrix4d tmp_m2;
  tmp_m1 << 0.401, -0.916,  0.007, 628491.906,
            0.916,  0.401,  0.000, 5177400.650,
           -0.003,  0.007,  1.000, 28.036,
            0,      0,      0,      1;
  tmp_m2 << 1.000,  0.012,  0.018,  4.603,
           -0.012,  1.000,  0.005,  2.428,
           -0.018, -0.006,  1.000,  0.005,
            0,      0,      0,      1;

  MatrixContainer test_matrices;
  test_matrices.m1 = tmp_m1;
  test_matrices.m2 = tmp_m2;
  DummyClass test_class;
  test_class.matrices = test_matrices;

  print4x4Matrix("A =", test_class.matrices.m1);
  print4x4Matrix("B =", test_class.matrices.m2);

  cout << "Multiplied and printed within the class function (incorrect)" << endl;
  test_class.multiplyMatrices();

  cout << "Multiplied and printed outside the class function (correct)" << endl;
  print4x4Matrix("C2 = AB =", tmp_m1*tmp_m2);
  return 0;
}

结果(在我演示错误的大型程序中)产生的是:

    |  0.401 -0.916  0.007 628491.906 | 
A = |  0.916  0.401  0.000 5177400.650 | 
    | -0.003  0.007  1.000 28.036 | 
    |  0      0      0      1     | 

    |  1.000  0.012  0.018  4.603 | 
B = | -0.012  1.000  0.005  2.428 | 
    | -0.018 -0.006  1.000  0.005 | 
    |  0      0      0      1     | 

Multiplied and printed within the class function (incorrect) 

          |  0.413 -0.911  0.009 -0.379 | 
C1 = AB = |  0.911  0.413  0.018  5.190 | 
          | -0.020  0.001  1.000  0.007 | 
          |  0      0      0      1     | 

Multiplied and printed outside the class function (correct)

          |  0.412 -0.911  0.010 628491.528 | 
C2 = AB = |  0.911  0.412  0.018 5177405.840 | 
          | -0.021  0.001  1.000 28.044 | 
          |  0      0      0      1     | 

我不知道为什么一个计算是正确的而另一个是错误的。

上面的代码与大型项目的一部分大致相同,唯一的区别是m1 / m2的值是使用数据文件中的值设置的,而不是显式设置的。然而,当我完全按照上面所示的那样执行代码时,在它自己的程序中,结果矩阵在两种情况下都是相同的(即C1和C2都是正确的)。

我已经有几位同事查看我的代码并尝试调试它,但没有成功。我还没有在Eigen bugzilla site或Stack Overflow上找到任何解释甚至是类似的问题。我发现的最接近的线索是In which cases do functions taking a plain Matrix or Array argument fail?上的Eigen文档,这表明编译器无法阻止您将特征矩阵复制到临时变量。但是,我的编译器并没有失败,正如我所说的,当上面的代码以它自己的程序运行时,C1和C2都是正确的。

不幸的是,我无法分享我的完整代码,无论如何要求任何人调试它都是不公平的。因此,我只是就可能导致此问题或任何类似问题的建议寻求建议。任何我可以研究的领导都将非常感激。

编辑1:我做的挖掘越多,内存对齐问题就越重要,以及当Eigen矩阵存储在类对象中时如何执行。在演示错误的代码中,我实际上使用嵌套对象 - 一个对象包含所有矩阵(MatrixContainer),另一个对象存储此对象类型的变量和一堆无关数据(DummyClass)。当我运行上面的缩减示例时,两个结果都是正确的(即C1 = C2),这就是为什么我当时认为它不重要的原因。但是我现在意识到可能不是这样,所以我已经改变了缩减的例子,以更准确地估计出错的版本正在做什么。

编辑2: Valgrind没有在代码的这一部分附近报告任何异常情况。 GDB也没有发现任何异常。两个矩阵(A和B)在代码的所有阶段都保持正确的值,因此在乘法运算期间肯定会发生错误。

编辑3:我发现使用Affine3d Eigen对象代替Matrix4d似乎可以避免这个问题。因此,如果我重复完全相同的操作并使用相同的函数,Affine3d乘法将产生正确的结果,而Matrix4d乘法则不会。

0 个答案:

没有答案