2012年11月24日土曜日

C vs Python vs Ruby vs Haskell(無意味な処理deベンチマーク)のC++版

memo.org

最近、nshinchan01さんのブログで、4つの言語を利用したコードの実行速度(しんちゃんの日記:C vs Python vs Ruby vs Haskell(無意味な処理deベンチマーク))の比較が行われていた。

TL上で、Haskellの実行速度がありえないほど早いのを見て興味を持ったので、C++11の 勉強がてら、C++版でお題の問題を書いて実行時間を計測してみた。

詳しくは、nshinchan01さんのブログを見て欲しいが、お題は、4000x4000整数の2次元配列arrayが あり、arrayの要素array[i][j]は、整数4000*i+j+1。arrayの各要素array[i](整数の配列)を反転して、 arrayの最後尾の要素の最後尾の要素を表示する処理の実行時間を測定する。

C++11で導入されたRangeベースのforループ、autoキーワードを用いた型推論を利用してお題を 解いてみると以下のようなコードになった。これを、clang++ version 3.0で、O3オプションを指定して コンパイル。

#include <algorithm>
#include <iostream>
#include <vector>

static const unsigned int N = 4000;
int main(int argc, char *argv[]) {
  std::vector<std::vector<int> > array(N,std::vector<int>(N));
  int i = 0;
  for (auto& a: array) {
    std::iota(a.begin(),a.end(),N*i+1);
    ++i;
  }
  for (auto& a: array) {
    std::reverse(a.begin(), a.end());
  }
  std::cout << array.back().back() << std::endl;
  return 0;
}

しんちゃんの日記:Haskellで実行時間計測用のコマンドを作る で作った、difftimeコマンドを利用して実行時間を測定。10回の平均を取ると、0.2824988secになった。

nshinchan01さんのブログに書いてある、Cのコードを同じ環境で測定した結果は、0.2928458secとなり、C++との差が3%程とC++でCのコードと遜色のないコードが書けることがわかる。(※ただ、nshinchan01さんのところではCのコードの実行時間が0.083と、手元の環境より3倍ほど早いのが気になる。コンパイラの違いかな?)

で、最初にC++で実装するきっかけとなったHaskellのコードだが、C/C++と同じ環境で測定すると0.0282011sec となり、C/C++の約10倍という圧倒的な性能となる(^^;) Haskell恐るべし。

ただ、Haskellって遅延評価(データが欲しいときに計算を実行する)なので、Haskellとその他の言語での実装を比較するときは、問題の設定方法に気をつけないとまともな比較にならない。

今回のお題では、4000x4000の配列を生成して(処理1)、その配列を反転して(処理2)、最後尾の要素の最後尾の要素を取得(処理3)する。3処理の実行時間を計測するというもの。C/C++のような命令型であれば、処理を順に書いていくだけで単純だけど、Haskellだと遅延評価のおかげで余分な処理を実行されないので、3つの処理が実際に実行されているかはわからないような気がする。(多分されていない)

ともかく、Haskell適切に書くと読み易く効率の良いコードが書けるのが素晴しい。C++でも、遅延評価の仕組みを取り入れてHaskellにせまる実行速度のコード書けるのかな?(そもそも最初は、Templateメタプログラミングでコンパイル時に問題を解いて答えを表示するだけのコードを実装しようとしたけど、コンパイルが終了しなかったorz)

2012-11-24 Sat 13:55