C++ 特征归约比简单循环慢

wco*_*ran 5 c++ linear-algebra eigen

给定两个 3xK 矩阵,我希望计算逐列点积的平方平均值。这可以通过一个简单的循环来完成:

Eigen::Matrix<float,3,Eigen::Dynamic> L(3,K);
Eigen::Matrix<float,3,Eigen::Dynamic> P(3,K);

float distance = 0;
for (int q = 0; q < K; q++){
    const Eigen::Vector3f& line = L.col(q);
    const Eigen::Vector3f& point = P.col(q);
    const float d = line.dot(point);
    distance += d*d;
 }
 const float residual2 = distance / K;
Run Code Online (Sandbox Code Playgroud)

其性能优于 ( g++ -O3 -DNDEBUG) 更高级的缩减技术,例如:

 const float residual2 = (L.array() * P.array()).colwise().sum().square().mean();
 const float residual2 = L.cwiseProduct(P).array().colwise().sum().array().square().mean();
 const float residual2 = (L.transpose() * P).diagonal().array().square().mean();
Run Code Online (Sandbox Code Playgroud)

也许我在这里缺少一些东西。削减不是应该更快吗?

编辑:使用 K = 20。我执行上述 100*632*631 次,循环版本大约需要 1200 毫秒,而其他版本大约需要 2000 毫秒。3.2 GHz 英特尔酷睿 i5、MacOS、clang++ -O3

Edit2:创建了一个小测试程序。添加-NDEBUG编译功能产生了巨大的差异(我以为你可以免费获得这个-O3)。循环版本明显快于缩减版本:

./eigentest
CASE 1: 12 milliseconds
solution = 1482.5
CASE 2: 835 milliseconds
solution = 1482.5
CASE 3: 849 milliseconds
solution = 1482.5
CASE 4: 843 milliseconds
solution = 1482.5
Run Code Online (Sandbox Code Playgroud)

Edit3:我认为上面的测试很糟糕,因为编译器展开了循环......叹息......我很快就会回到这个......