Eigen库:那些年我们一起经历的bug

编程技术  /  houtizong 发布于 3年前   153
1、使用auto声明新变量时不要局部eval()
这句话神马意思呢? 我们知道,在C++函数中最好不要返回局部变量,否则可能产生因为局部变量被回首而引发的错误。
而这个问题正是源于此。
在以下这个bug中:
http://eigen.tuxfamily.org/bz/show_bug.cgi?id=505 
“a*b”就会引发自动的eval(),从而产生局部变量,该局部变量被一个表达式所引用,导致结果不可预知。
最新版本的Eigen已经解决了这个问题~~~那么,这个bug是不是完全不存在了呢?
答案是NO。。。。
看以下的代码:

    auto A_mul_B_plus_C = C + (A * B).colwise().sum();    auto A_mul_B_Eval_plus_C = C + (A * B).colwise().sum().eval();

二者的结果都是表达式,但是第二个表达式中局部变量被eval()了,产生了一个临时的Matrix,该临时变量会被回收,导致结果的不正确。
解决方案:
  • 1、不使用auto A_mul_B_Eval_plus_C,而是使用MatrixXd A_mul_B_Eval_plus_C这类的显式声明。(但这样不够灵活有没有!)
  • 2、使用eval(),对,你没看错,但是是在整条语句上使用eval();比如:auto A_mul_B_plus_C_EvalAll = (C + (A * B).colwise().sum().eval() ).eval(); //如果该变量要多次使用,推荐这种做法,这种做法也是最安全的(不会因为Eigen库还有之前a*b产生局部变量引发的错误)
  • 3、完全不使用eval(); 比如:auto A_mul_B_plus_C = C + (A * B).colwise().sum();

完整的代码参见:http://eigen.tuxfamily.org/bz/show_bug.cgi?id=883
更深入了解这个bug看下面这个链接:http://eigen.tuxfamily.org/bz/show_bug.cgi?id=99

2、不用eval()也是不行的!(最新版本(3.2.2)不存在这个问题了)
也许你会有所疑问,我干嘛要手动eval()呢?
这源于另一个bug:
一年前接触Eigen库的时候,写过这么一段代码

      Eigen::MatrixXd m=Eigen::MatrixXd::Ones(3,4);      m.array().rowwise()/=m.array().colwise().sum();      std::cout<<m<<std::endl;

结果大跌眼镜(最新版本的输出没问题了):
  • 0.333333 0.333333 0.333333 0.333333
  • 0.428571 0.428571 0.428571 0.428571
  • 0.567568 0.567568 0.567568 0.567568

原因可能是等号右边时表达式,左边每行除以右边时,右边的表达式都会被重新计算。。。
所以当时的版本必须eval()一下!好在现在这个bug消除了!
另外多说一句,基于效率考虑,可能也要eval()一下,但是我调了下代码,当前版本的Eigen右侧的表达式是只计算一遍的,放心的不eval()吧!

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!

留言需要登陆哦

技术博客集 - 网站简介:
前后端技术:
后端基于Hyperf2.1框架开发,前端使用Bootstrap可视化布局系统生成

网站主要作用:
1.编程技术分享及讨论交流,内置聊天系统;
2.测试交流框架问题,比如:Hyperf、Laravel、TP、beego;
3.本站数据是基于大数据采集等爬虫技术为基础助力分享知识,如有侵权请发邮件到站长邮箱,站长会尽快处理;
4.站长邮箱:[email protected];

      订阅博客周刊 去订阅

文章归档

文章标签

友情链接

Auther ·HouTiZong
侯体宗的博客
© 2020 zongscan.com
版权所有ICP证 : 粤ICP备20027696号
PHP交流群 也可以扫右边的二维码
侯体宗的博客