C++;数字代码(使用Eigen)速度惊人地慢 我是一个物理学家,用Matlab/Python/朱丽亚编写代码,考虑使用C++来处理一些性能敏感的代码。我已经写了一个最感兴趣的功能,目前我感兴趣的是Rotne Prager张量的计算-以一个简洁的基准的形式,并实现了它在C++,朱丽亚和MATLAB。C++版本目前比朱丽亚代码慢8倍,这导致我得出了一些可怕的C++的结论。守则内容如下: #include "stdafx.h" #include <iostream> #include <random> #include <chrono> #include <Eigen/Dense> using namespace Eigen; using namespace std; using namespace std::chrono; Matrix3d outer_product_3d(Vector3d a, Vector3d b) { Matrix3d m; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { m(i, j) = a(i) * b(j); } } return m; } MatrixXd rotne_prager(Vector3d coords[], double r, const int p) { MatrixXd rpy = MatrixXd::Zero(3*(p+1),3*(p+1)); Vector3d rvec; double Rij; double distance_ratio; Matrix3d I = Matrix3d::Identity(3, 3); for (int i = 0; i < p + 1; i++) { for (int j = 0; j < p + 1; j++) { rvec(0) = coords[j](0) - coords[i](0); rvec(1) = coords[j](1) - coords[i](1); rvec(2) = coords[j](2) - coords[i](2); Rij = sqrt(rvec(0)*rvec(0) + rvec(1)*rvec(1) + rvec(2)*rvec(2)); distance_ratio = r / Rij; if (Rij > 2 * r) { rpy.block(3 * (i + 1) - 3, 3 * (j + 1) - 3, 3, 3) = 0.75 * distance_ratio * ((1.0 + 2.0 / 3.0 * distance_ratio * distance_ratio) * I + (1.0 - 2.0*distance_ratio * distance_ratio) * outer_product_3d(rvec, rvec)); } else { rpy.block(3 * (i + 1) - 3, 3 * (j + 1) - 3, 3, 3) = (1.0 - 9.0 / 32.0 / distance_ratio) * I + 3.0 / 32.0 / distance_ratio * outer_product_3d(rvec, rvec); } } } return rpy; } int main() { random_device rd; mt19937 gen(rd()); uniform_real_distribution<> dis(0, 1); auto start = high_resolution_clock::now(); const int p = 1000; Vector3d coords[p + 1]; for (int i = 0; i < p + 1; i++) { coords[i](0) = dis(gen); coords[i](1) = dis(gen); coords[i](2) = dis(gen); } MatrixXd rpy = rotne_prager(coords, 0.01, p); auto end = high_resolution_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); cout << "p = " << p << ", time elapsed: " << duration << " ms" << endl; } rpy.block<3,3>(3 * (i + 1) - 3, 3 * (j + 1) - 3) = ((1.0 - 2.0*distance_ratio * distance_ratio) * rvec) * rvec.transpose(); rpy.block<3,3>(3 * (i + 1) - 3, 3 * (j + 1) - 3).diagonal().array() += 0.75 * distance_ratio * ((1.0 + 2.0 / 3.0 * distance_ratio * distance_ratio); #包括“stdafx.h” #包括 #包括 #包括 #包括 使用名称空间特征; 使用名称空间std; 使用名称空间std::chrono; 矩阵3d外部产品3d(矢量3d a、矢量3d b) { 矩阵x3d-m; 对于(int i=0;i
首先,确保您在VisualStudio中使用编译器优化(也称为C++;数字代码(使用Eigen)速度惊人地慢 我是一个物理学家,用Matlab/Python/朱丽亚编写代码,考虑使用C++来处理一些性能敏感的代码。我已经写了一个最感兴趣的功能,目前我感兴趣的是Rotne Prager张量的计算-以一个简洁的基准的形式,并实现了它在C++,朱丽亚和MATLAB。C++版本目前比朱丽亚代码慢8倍,这导致我得出了一些可怕的C++的结论。守则内容如下: #include "stdafx.h" #include <iostream> #include <random> #include <chrono> #include <Eigen/Dense> using namespace Eigen; using namespace std; using namespace std::chrono; Matrix3d outer_product_3d(Vector3d a, Vector3d b) { Matrix3d m; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { m(i, j) = a(i) * b(j); } } return m; } MatrixXd rotne_prager(Vector3d coords[], double r, const int p) { MatrixXd rpy = MatrixXd::Zero(3*(p+1),3*(p+1)); Vector3d rvec; double Rij; double distance_ratio; Matrix3d I = Matrix3d::Identity(3, 3); for (int i = 0; i < p + 1; i++) { for (int j = 0; j < p + 1; j++) { rvec(0) = coords[j](0) - coords[i](0); rvec(1) = coords[j](1) - coords[i](1); rvec(2) = coords[j](2) - coords[i](2); Rij = sqrt(rvec(0)*rvec(0) + rvec(1)*rvec(1) + rvec(2)*rvec(2)); distance_ratio = r / Rij; if (Rij > 2 * r) { rpy.block(3 * (i + 1) - 3, 3 * (j + 1) - 3, 3, 3) = 0.75 * distance_ratio * ((1.0 + 2.0 / 3.0 * distance_ratio * distance_ratio) * I + (1.0 - 2.0*distance_ratio * distance_ratio) * outer_product_3d(rvec, rvec)); } else { rpy.block(3 * (i + 1) - 3, 3 * (j + 1) - 3, 3, 3) = (1.0 - 9.0 / 32.0 / distance_ratio) * I + 3.0 / 32.0 / distance_ratio * outer_product_3d(rvec, rvec); } } } return rpy; } int main() { random_device rd; mt19937 gen(rd()); uniform_real_distribution<> dis(0, 1); auto start = high_resolution_clock::now(); const int p = 1000; Vector3d coords[p + 1]; for (int i = 0; i < p + 1; i++) { coords[i](0) = dis(gen); coords[i](1) = dis(gen); coords[i](2) = dis(gen); } MatrixXd rpy = rotne_prager(coords, 0.01, p); auto end = high_resolution_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); cout << "p = " << p << ", time elapsed: " << duration << " ms" << endl; } rpy.block<3,3>(3 * (i + 1) - 3, 3 * (j + 1) - 3) = ((1.0 - 2.0*distance_ratio * distance_ratio) * rvec) * rvec.transpose(); rpy.block<3,3>(3 * (i + 1) - 3, 3 * (j + 1) - 3).diagonal().array() += 0.75 * distance_ratio * ((1.0 + 2.0 / 3.0 * distance_ratio * distance_ratio); #包括“stdafx.h” #包括 #包括 #包括 #包括 使用名称空间特征; 使用名称空间std; 使用名称空间std::chrono; 矩阵3d外部产品3d(矢量3d a、矢量3d b) { 矩阵x3d-m; 对于(int i=0;i,c++,performance,numeric,eigen,numerical,C++,Performance,Numeric,Eigen,Numerical,首先,确保您在VisualStudio中使用编译器优化(也称为Release模式)进行了基准测试 其次,outer\u product\u 3d函数的用途是什么,为什么不执行rvec*rvec.transpose() 最后,您可以显著减少操作计数,如下所示: #include "stdafx.h" #include <iostream> #include <random> #include <chrono> #include <Eigen/Dense&g
Release
模式)进行了基准测试
其次,outer\u product\u 3d
函数的用途是什么,为什么不执行rvec*rvec.transpose()
最后,您可以显著减少操作计数,如下所示:
#include "stdafx.h"
#include <iostream>
#include <random>
#include <chrono>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;
using namespace std::chrono;
Matrix3d outer_product_3d(Vector3d a, Vector3d b)
{
Matrix3d m;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
m(i, j) = a(i) * b(j);
}
}
return m;
}
MatrixXd rotne_prager(Vector3d coords[], double r, const int p)
{
MatrixXd rpy = MatrixXd::Zero(3*(p+1),3*(p+1));
Vector3d rvec;
double Rij;
double distance_ratio;
Matrix3d I = Matrix3d::Identity(3, 3);
for (int i = 0; i < p + 1; i++)
{
for (int j = 0; j < p + 1; j++)
{
rvec(0) = coords[j](0) - coords[i](0);
rvec(1) = coords[j](1) - coords[i](1);
rvec(2) = coords[j](2) - coords[i](2);
Rij = sqrt(rvec(0)*rvec(0) + rvec(1)*rvec(1) + rvec(2)*rvec(2));
distance_ratio = r / Rij;
if (Rij > 2 * r)
{
rpy.block(3 * (i + 1) - 3, 3 * (j + 1) - 3, 3, 3) =
0.75 * distance_ratio * ((1.0 + 2.0 / 3.0 * distance_ratio * distance_ratio) * I
+ (1.0 - 2.0*distance_ratio * distance_ratio) * outer_product_3d(rvec, rvec));
}
else
{
rpy.block(3 * (i + 1) - 3, 3 * (j + 1) - 3, 3, 3) =
(1.0 - 9.0 / 32.0 / distance_ratio) * I +
3.0 / 32.0 / distance_ratio * outer_product_3d(rvec, rvec);
}
}
}
return rpy;
}
int main()
{
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<> dis(0, 1);
auto start = high_resolution_clock::now();
const int p = 1000;
Vector3d coords[p + 1];
for (int i = 0; i < p + 1; i++)
{
coords[i](0) = dis(gen); coords[i](1) = dis(gen); coords[i](2) = dis(gen);
}
MatrixXd rpy = rotne_prager(coords, 0.01, p);
auto end = high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
cout << "p = " << p << ", time elapsed: " << duration << " ms" << endl;
}
rpy.block<3,3>(3 * (i + 1) - 3, 3 * (j + 1) - 3) = ((1.0 - 2.0*distance_ratio * distance_ratio) * rvec) * rvec.transpose();
rpy.block<3,3>(3 * (i + 1) - 3, 3 * (j + 1) - 3).diagonal().array() += 0.75 * distance_ratio * ((1.0 + 2.0 / 3.0 * distance_ratio * distance_ratio);
rpy.block(3*(i+1)-3,3*(j+1)-3)=((1.0-2.0*距离比*距离比)*rvec)*rvec.transpose();
rpy.块(3*(i+1)-3,3*(j+1)-3.对角线().数组()+=0.75*距离比*((1.0+2.0/3.0*距离比*距离比);
在第一行中,避免将缩放应用到<代码> 3x3矩阵,只将它应用到<代码> 3x1向量中。第二行保存6个附加项。同样适用于<代码>其他< /代码>分支。< /P>如果您有要优化的工作代码,则应考虑将此问题发布到CoDeEvIEW.StAccExchange。COMT。谢谢你的建议,我以后会把这些问题发布到codereview.stackexchange.com上。请记住,ColumWise(类似fortran)是Eigen的默认存储顺序-因此具有第一个索引,即
I
在m(I,j)中
,最好是内部的。谢谢你的优化,我没有想到。我之所以有外部产品的3d函数,是因为在我以前使用过的几乎所有语言中,这种方法都比该语言拥有的任何通用外部产品函数快得多。幸运的是,Eigen不是这样的在C++中,RVEC*RVEC。TrasoSoE()方法比10%快。