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++;数字代码(使用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

首先,确保您在VisualStudio中使用编译器优化(也称为
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%快。