メモの日々


2017年03月03日(金) [長年日記]

[c][c++] exp10()

glibcにexp10という関数があることを知った。pow10もある。

exp10はCやC++の今の標準ライブラリには入っていない。いずれ入るのかな。

手元の環境(CentOS 7, GCC 4.8.5)だと、<cmath>をincludeすればC++でexp10を使えた。Cの場合は_GNU_SOURCEをdefineしてから<math.h>をincludeしないと警告が出る。

[c++] exp10()とstd::pow()とstd::exp()

10のべき乗を計算するプログラムでstd::powを使っていたのだけれど、結構遅い。代わりにexp10を使ったら少し速くなった。exp10を標準化して欲しい。

ところで、10^x は

10^x = (e^log(10))^x = e^(log(10) * x)

と変換できるので、std::expを使っても計算できる。試すと、これが一番速かった。xの範囲によって計算の速度が変わるのかもしれないけれど。以下に、xが0の近辺で10^xを計算するプログラムとその実行結果を示す。

#include <chrono>
#include <cmath>
#include <iomanip>
#include <iostream>

template<typename F>
void call(const std::string& name, F f) {
  using namespace std::chrono;
  constexpr int n = 10000000;
  constexpr double d = 0.0001;

  const auto s = system_clock::now();
  double r = 1;
  for (int i = -n; i <= n; ++i) {
    r *= f(d * i / n);
  }
  const auto e = system_clock::now();

  std::cout
      << std::setprecision(20)
      << r
      << ", " << duration_cast<milliseconds>(e - s).count() << " ms"
      << ", " << name
      << std::endl;
}

int main() {
  call("std::pow", [](double x) {
    return std::pow(10.0, x);
  });
  call("exp10", [](double x) {
    return exp10(x);
  });
  call("std::exp", [](double x) {
    constexpr double log_10 = std::log(10);
    return std::exp(log_10 * x);
  });
}
1.0389215324922376205, 2650 ms, std::pow
1.0389215324948466446, 2371 ms, exp10
1.0389215324923555261, 1832 ms, std::exp