我确实使用Valgrind(使用“发布带有调试信息的版本”版本)对我的代码进行了概要分析,发现在计算大矩阵的逐元素立方根的一行上花费了大量时间(〜25%) 。
现在,如果可能的话,我想加快这一步。
目前,我只是在使用.pow( 1.0 / 3.0)。我想知道是否可以通过使用std::cbrt()来改善它?但是,如何将此函数传递给Eigen以便进行元素级立方根?

#include "iostream"
#include "eigen-3.3.7/Eigen/Dense"

using namespace Eigen;
int main() {
  // generate some random numbers
  VectorXd v = VectorXd::Random(10).array().abs() ;
  std::cout << v << std::endl << std::endl ;

  // calculate the cubic root
  VectorXd s = v.array().pow( 1.0 / 3.0 );
  std::cout << s << std::endl;
}

最佳答案

您可以使用DenseBase::unaryExpr和C++ lambda:

VectorXd s = v.unaryExpr([](double coeff){ return std::cbrt(coeff); });
使用Google Benchmark的小型基准测试:
#include <Eigen/Dense>
#include <benchmark/benchmark.h>

using namespace Eigen;

static void BM_Pow(benchmark::State& state)
{
  VectorXd v = VectorXd::Random(state.range(0)).array().abs();
  VectorXd s;
  for (auto _ : state) {
    benchmark::DoNotOptimize(s = v.array().pow( 1.0 / 3.0 ));
    benchmark::ClobberMemory();
  }
}

static void BM_Cbrt(benchmark::State& state)
{
  VectorXd v = VectorXd::Random(state.range(0)).array().abs();
  VectorXd s;
  for (auto _ : state) {
    benchmark::DoNotOptimize(s = v.unaryExpr([](double coeff){ return std::cbrt(coeff); }));
    benchmark::ClobberMemory();
  }
}

BENCHMARK(BM_Pow) -> Range(4, 10000);
BENCHMARK(BM_Cbrt) -> Range(4, 10000);

BENCHMARK_MAIN();
使用-O3进行编译在我的机器上提供了以下内容:
-----------------------------------------------------
Benchmark              Time           CPU Iterations
-----------------------------------------------------
BM_Pow/4              69 ns         69 ns   10099698
BM_Pow/8             134 ns        134 ns    5391874
BM_Pow/64           1043 ns       1043 ns     673401
BM_Pow/512          8476 ns       8474 ns      82371
BM_Pow/4096        68708 ns      68702 ns      10839
BM_Pow/10000      160833 ns     160566 ns       4222
BM_Cbrt/4             23 ns         23 ns   31538209
BM_Cbrt/8             45 ns         45 ns   15129345
BM_Cbrt/64           358 ns        358 ns    1968338
BM_Cbrt/512         2810 ns       2809 ns     254678
BM_Cbrt/4096       23926 ns      23855 ns      31430
BM_Cbrt/10000      55692 ns      55568 ns      12765
所以这似乎是值得的。

07-24 18:58