不存储中间结果时,本征给出错误结果

Dav*_*vid 6 c++ eigen

为牛顿法编写一个实现雅可比矩阵的函数,我注意到一个非常严重的错误。

调用函数

auto DF = [T](VectorXd y){
    return PhiAndW(y(0),y(1),T).second - MatrixXd::Identity(2,2);
 };
Run Code Online (Sandbox Code Playgroud)

只返回 的值PhiAndW(y(0),y(1),T).second并省略 的减法MatrixXd::Identity(2,2)。但是如果我将代码更改为

auto DF = [T](VectorXd y){
    MatrixXd mat = PhiAndW(y(0),y(1),T).second - MatrixXd::Identity(2,2);
    return mat;
 };
Run Code Online (Sandbox Code Playgroud)

一切顺利。

我试图重现它,这不是完全相同的行为,但它的行为也不如预期:

考虑以下代码:

MatrixXd FF(MatrixXd y){
  return y;
}

int other(){

  auto DF = [](MatrixXd y){
    MatrixXd test = FF(y)  - MatrixXd::Identity(2,2);
    return test;
  };

  std::cout << DF(MatrixXd::Ones(2,2)) <<std::endl;
  std::cout << std::endl;
  std::cout << (MatrixXd::Ones(2,2) - MatrixXd::Identity(2,2))<< std::endl;

}
Run Code Online (Sandbox Code Playgroud)

它会打印

>  1 0
>  0 1 
>
>  1 0 
>  0 1 
Run Code Online (Sandbox Code Playgroud)

到控制台。

但是,如果我改变功能DF,以

  auto DF = [](MatrixXd y){
    return FF(y)  - MatrixXd::Identity(2,2);
  };
Run Code Online (Sandbox Code Playgroud)

控制台将打印

>  2.22045e-15 1.63042e-322
>  2.37152e-322    -0.999998
Run Code Online (Sandbox Code Playgroud)

对于第二个矩阵。(这只是内存中一些未初始化的垃圾)。

有人可以解释我的代码和示例问题发生了什么。我真的不知道这里发生了什么。我特别感兴趣的是为什么将计算结果保存在临时变量中可以解决这个问题。

Dav*_*vid 4

由于评论几乎解决了我的问题(非常感谢),我想我应该继续回答我的问题,以便其他人看到这个问题已经解决。

为什么会出现这个问题?

问题在于,例如两个矩阵的本征乘法的结果类型不是本征矩阵,而是一些表示乘法并引用我们要相乘的两个矩阵的内部对象。

因此,如果我们使用auto关键字,编译器很可能不会给出我们正在设置类型的变量MatrixXd,而是给出某些内部对象的类型。

有关更多信息,请参阅Eigen 文档,其中明确指出:

简而言之:不要将 auto 关键字与 Eigen 表达式一起使用,除非您 100% 确定自己在做什么。特别是,不要使用 auto 关键字来替代 Matrix<> 类型

我该如何防止这种情况发生?

  • 不要使用auto关键字,使用显式类型。
  • 对于 lambda 函数,始终指定返回类型:Writeauto DF = []() -> MatrixXd {...}而不是auto DF = []() {...}