Eigen 中立方根的性能改进

use*_*005 3 c++ performance eigen

我确实使用 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;
}
Run Code Online (Sandbox Code Playgroud)

dte*_*ell 5

您可以使用DenseBase::unaryExprC++ lambda:

VectorXd s = v.unaryExpr([](double coeff){ return std::cbrt(coeff); });
Run Code Online (Sandbox Code Playgroud)

使用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();
Run Code Online (Sandbox Code Playgroud)

-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
Run Code Online (Sandbox Code Playgroud)

所以这似乎是值得的。