boost::numeric::ublas::vectorの速度比較
boost/numeric/ublas/vectorの生成と代入に関する速度をまとめた。
要素数を5千万にして生成と代入の速度を計測。
compiler及び環境
- i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)
- Macbookair 2013mid
clock関数で時間を計測。時間の分解能はμ秒。
時間はコンパイル時にO2
オプションをつけた時と付けない時の時間を記載。
生成と初期化の速度
まとめ
ublas::vector
とstd::vector
の生成に関する時間の差はなし。vectorのfor文での全要素の走査は生成の6倍程度の時間がかかる。但し、O2オプションをつければ生成と同程度の時間ですむ。
- 生成後の代入操作はなるべく避ける。
std::vector
の生成の時間
std::vector<double> vec1(num, 2.0);
上記コードのstd::vector
の生成の時間は
- O2なし:0.379705[sec]
- O2あり:0.244777[sec]
boost::numeric::ublas::vector
の生成の時間
boost::numeric::ublas::vector<double> vec3(num, 1.2);
上記コードのboost::numeric::ublas::vector
の生成の時間
- O2なし:0.408235[sec]
- O2あり:0.249085[sec]
boost::numeric::ublas::vector
の走査時間
for (std::size_t index = 0; index < num; ++index) { vec3[index] = index / 2.0; }
上記コードのboost::numeric::ublas::vector
の走査時間
- O2なし:1.27493[sec]
- O2あり:O2:0.279947[sec]
代入に関する時間
前提として下記コード内のvec2,vec3
は以下のように要素数5千万のublas::vector
として宣言されているとする。
const std::size_t num = 50000000; boost::numeric::ublas::vector<double> vec2(num); boost::numeric::ublas::vector<double> vec3(num);
まとめ
vec2=vec3
の代入が最も高速。for文での要素毎の代入は
vec2=vec3
の4倍程度かかる。関数への参照渡しは要素数にかかわらずほぼ時間0と考えて良い。
関数への実体渡しは、vectorの生成にかかる時間と同程度かやや遅い。
関数への実体戻しでの代入は、for文での代入と同じくらい遅い。
参照渡しで関数内で
vec2=vec3
をするのと、関数外でvec2=vec3
は速度はほぼ同じ。
vec2=vec3
の速度
vec3[1] = vec2[10]; vec2 = vec3; vec2[1] = vec3[2];
- O2なし:0.079151
- O2あり:0.075633
for文による要素毎の代入の速度速度
for (std::size_t index = 0; index < num; ++index) { vec2[index] = vec3[index]; }
- O2なし:1.83324
- O2あり:0.3431
生成のときのfor文の倍の時間かかっているのは、operator[]
が二個あるため。
関数の参照渡しと戻り値を実体戻し
boost::numeric::ublas::vector<double> hoge( boost::numeric::ublas::vector<double>& vec) { return vec; } vec3 = hoge(vec2);
- O2なし:0.408114
- O2あり:0.317184
for文と同じくらい遅い
関数の参照渡しと参照戻し
boost::numeric::ublas::vector<double>& hoge2( boost::numeric::ublas::vector<double>& vec) { return vec; } vec3 = hoge2(vec2);
- O2なし:0.073233
- O2あり:0.075371
おそらく、vec2=vec3
と内部的には同じ動作。
参照渡しにかかる時間
void hoge3( boost::numeric::ublas::vector<double>& vec) { } hoge3(vec3);
- O2なし:1e-06
- O2あり:0
参照渡しにかかる時間はほぼゼロ。O2
で0[sec]になっているのはおそらく関数内にコードがないので、関数呼び出しを省略されたため。
関数の実体渡しにかかる時間
void hoge4( boost::numeric::ublas::vector<double> vec) { } hoge4(vec3);
- O2なし:0.264846
- O2あり:0.249281
実体渡しは生成とほぼ同じ時間がかかる。
参照渡しで関数内でvec2=vec3
void hoge5( boost::numeric::ublas::vector<double>& vec, boost::numeric::ublas::vector<double>& vec2) { vec2 = vec; } hoge5(vec2, vec3);
- O2なし:0.075753
- O2あり:0.074778
コード全体
時間は時間計測開始部分にコメントで以下のように付与している。
//O2オプションなしの時間[sec] //O2オプションありの時間[sec] start = clock() //処理など
#include <boost/numeric/ublas/vector.hpp> #include <vector> #include <time.h> boost::numeric::ublas::vector<double> hoge( boost::numeric::ublas::vector<double>& vec) { return vec; } boost::numeric::ublas::vector<double>& hoge2( boost::numeric::ublas::vector<double>& vec) { return vec; } void hoge3( boost::numeric::ublas::vector<double>& vec) { } void hoge4( boost::numeric::ublas::vector<double> vec) { } void hoge5( boost::numeric::ublas::vector<double>& vec, boost::numeric::ublas::vector<double>& vec2) { vec2 = vec; } int main(int argc, char const* argv[]) { namespace ublas = boost::numeric::ublas; const std::size_t num = 50000000; //0.379705 //O2:0.244777 clock_t start = clock(); std::vector<double> vec1(num, 2.0); clock_t end = clock(); double duraiton = static_cast<double>((end - start)) / CLOCKS_PER_SEC; std::cout << "duration1:" << duraiton << std::endl; boost::numeric::ublas::vector<double> vec2(num, 1.0); for (std::size_t index = 0; index < num; ++index) { vec2[index] = index; } //0.408235 //O2:0.249085 start = clock(); boost::numeric::ublas::vector<double> vec3(num, 1.2); end = clock(); duraiton = static_cast<double>((end - start)) / CLOCKS_PER_SEC; std::cout << "duration2:" << duraiton << std::endl; //1.27493 //O2:0.279947 start = clock(); for (std::size_t index = 0; index < num; ++index) { vec3[index] = index / 2.0; } end = clock(); duraiton = static_cast<double>((end - start)) / CLOCKS_PER_SEC; std::cout << "duration3:" << duraiton << std::endl; //0.118211 //O2:0.103219 start = clock(); vec3[1] = vec2[10]; vec2 = vec3; vec2[1] = vec3[2]; end = clock(); duraiton = static_cast<double>((end - start)) / CLOCKS_PER_SEC; std::cout << "duration4:" << duraiton << std::endl; //2.2732 //O2:0.446582 start = clock(); for (std::size_t index = 0; index < num; ++index) { vec2[index] = vec3[index]; } end = clock(); duraiton = static_cast<double>((end - start)) / CLOCKS_PER_SEC; std::cout << "duration5:" << duraiton << std::endl; //0.422054 //O2:0.421855 start = clock(); vec3 = hoge(vec2); end = clock(); duraiton = static_cast<double>((end - start)) / CLOCKS_PER_SEC; std::cout << "duration6:" << duraiton << std::endl; //0.119685 //O2:0.115396 start = clock(); vec3 = hoge2(vec2); end = clock(); duraiton = static_cast<double>((end - start)) / CLOCKS_PER_SEC; std::cout << "duration7:" << duraiton << std::endl; //1e-06 //O2:0 start = clock(); hoge3(vec3); end = clock(); duraiton = static_cast<double>((end - start)) / CLOCKS_PER_SEC; std::cout << "duration8:" << duraiton << std::endl; //0.346663 //O2:0.259321 start = clock(); hoge4(vec3); end = clock(); duraiton = static_cast<double>((end - start)) / CLOCKS_PER_SEC; std::cout << "duration9:" << duraiton << std::endl; //0.074641 //O2:0.075302 start = clock(); hoge5(vec2, vec3); end = clock(); duraiton = static_cast<double>((end - start)) / CLOCKS_PER_SEC; std::cout << "duration10:" << duraiton << std::endl; return 0; }
C++のclassとstructの違い
はっきりとした言及があまりなかったので一応メモ。
Cにおいてclassとstructは(Cには記憶クラスというものがあって)全くの別物だが、C++ではstructとclassに機能的な違いはない。
structとclassの違い
振る舞いとしての唯一の違いはデフォルトのアクセス指定子の違いである。
- struct
- デフォルトで
public
- デフォルトで
- class
- デフォルトで
private
- デフォルトで
struct hoge{ int h; }; class hage { int h; }; int main() { hoge hoge_instance; hage hage_instance; hoge_instance.h = 1; //OK //hage_instance.h = 1; //NG return 0; }
次のように書けば等価
struct hoge{ public://かかなくても良いが int h; }; class hage { public: int h; }; int main() { hoge hoge_instance; hage hage_instance; hoge_instance.h = 1; //OK hage_instance.h = 1; //OK return 0; }
structとclassの使い分け
以下に使い分けに関して言及がある。
oop - What are the differences between struct and class in C++? - Stack Overflow
要点をまとめると
C++のstaticに関するまとめ
static(メンバ)変数への代入について知識がうろ覚えだったので、整理した。要点は以下。
- staticな変数は宣言と同時に代入する
- staticなstruct型の初期化は{}で行う.
- class内のstaticなメンバに代入するときはクラスの宣言の外で代入.また型の指定が必要.
- class内struct型がprivateに宣言されていてもクラスの外で初期化できる
- class templateのstaticなメンバ変数、関数への代入はtemplateを指定する
- staticな関数ポインタはtemplate関数で初期化できる
前提知識1
前提知識として関数ポインタの宣言は以下のようにする。
引数名は省略可能。
戻り値 (*変数名)(引数型1 引数名1, 引数型2 引数名2, 続く) void (*hensu_mei)(void* hoge, double* hage);
前提知識2
c++はstruct
型とclass
は(メンバの宣言がデフォルトでpublicかどうかの違いはあるが)基本的に区別がない。
1. staticな変数は宣言と同時に代入する
よくみる構文なので当たり前だが、後述のstaticメンバの初期化とはちょっと異なるのに注意がいる。
/****************************************************************************** * staticな変数は宣言と同時に代入. ******************************************************************************/ void static_test_f0(void*) { } static void (*static_test_fp)(void *) = static_test_f0; //OK //static void (*static_test_fp)(void* hoge); //static_test_fp = static_test_f0; //NG
2. staticなstruct型の初期化は{}で行う.
staticなstruct型の場合。{}
記号の一つの用法。
/****************************************************************************** * staticなstruct型の初期化は{}で行う. ******************************************************************************/ void static_class_test_f(void *) { } struct static_class_test { void (*test)(void *); double hoge; }; static struct static_class_test static_class_test_instance = { static_class_test_f, 1.0 };
3. class内のstaticなメンバに代入するときはクラスの宣言の外で代入. また型の指定が必要.
staticな変数のとの大きな違いは下記。 * staticの宣言と代入を別の場所で行う * 型の指定が必要になる
/****************************************************************************** * class内のstaticなメンバに代入するときはクラスの宣言の外で代入. * また型の指定が必要. ******************************************************************************/ void static_test_f1(void*) { } class static_test1 { public: static_test1() {}; static void (*test)(void *); //static void (*test)(void *) = static_test_f1; //NG //void (*test)(void *) = static_test_f1; //NG static double hoge; //static double hoge = 1.0; //NG }; void (*static_test1::test)(void *) = static_test_f1; //static_test1::test = static_test_f1; //NG double static_test1::hoge = 1.0; //static_test1::hoge = 1.0; //NG
4. class内struct型がprivateに宣言されていてもクラスの外で初期化できる
staticなstruct型のメンバも上記2と3の組み合わせで代入できる。
注意すべき点はstaticなstruct型がprivateなクラス内struct型であっても問題ないという所。
/****************************************************************************** * class内struct型がprivateに宣言されていてもクラスの外で初期化できる ******************************************************************************/ class initialize_struct_test1 { private: struct vtable { void (*draw)(void*); double hoge; }; public: initialize_struct_test1(); static vtable _vTable; }; void test1(void *hoge) { //initialize_struct_test1::vtable hage; //NG } initialize_struct_test1::vtable initialize_struct_test1::_vTable = { test1, 2.0 }; //instaneがないので.は使えない //void (*initialize_struct_test1::_vTable.test)(void*) = test2; //NG //double initialize_struct_test1::_vTable.hoge = 2.0; //NG
5. class templateのstaticの時はtemplateも指定する
class templateにstaticなメンバがあるときはtemplateを指定して代入する。
/****************************************************************************** * class templateのstaticの時はtemplateも指定する ******************************************************************************/ template <typename T> class class_teplate_test { public: class_teplate_test(); static void (*test)(void*); static double hoge; }; void test2(void *hoge) { } template <typename T> void (*class_teplate_test<T>::test)(void *) = test2; template <typename T> double class_teplate_test<T>::hoge = 10.0;
6. staticな関数ポインタはtemplate関数で初期化できる
staticな関数ポインタに限った話ではないが、template関数の用法。
/****************************************************************************** * staticなtemplate関数はtemplateの指定が必要. ******************************************************************************/ template <typename T> void template_func_test_f1(T*) { } void template_func_test_f2(int*) { } static void (*template_func_test)(char*) = template_func_test_f1; //こういうのがやりたいならメタプログラミング //template <typename T> //static void (*template_func_test)(T*) = template_func_test_f2;
参考
nullptrまとめ
C++11から追加されたnullptr
のまとめ
概要
More C++ Idioms/nullptr - Wikibooks
ライブラリ版
C++0x nullptr の実装 - Faith and Brave - C++で遊ぼう
ライブラリ版の問題
C++の組み込み型はクラスとして扱える
タイトル通り。
doubleという名前のクラスと思って以下でdoubleの値を生成できる。
double a = double() double b = double(1.0)
ポインタも同様のことが可能だがtypedef
が必要
double* a = double*(); //error double* b = (double*)(); //error typedef double* pointer; double* c = pointer();
例
#include <iostream> struct Test { typedef double value_type; typedef double* pointer_type; }; void test(double test) { std::cout << "double" << std::endl; } void test(Test::value_type*) { std::cout << "pointer" << std::endl; } int main(int argc, char const* argv[]) { double a = double(); double b = double(1.0); double c = double(b); std::cout << a << ", " << b << ", " << c<< std::endl; //実行結果 //0, 1, 1 test(Test::value_type()); test(Test::pointer_type()); //実行結果 //double //pointer //double *d = (double*)(); //error double *d = Test::pointer_type(); double *e = Test::pointer_type(&a); std::cout << d << ", " << e << std::endl; //実行結果 //0, 0x7fff57530970 return 0; }
ディレクトリ以下の特定ディレクトリを除外しファイル列挙
特定のディレクトリを除外して、カレントディレクトリ以下のファイルを列挙する。例えば、include
を除いて、.h
ファイルを全部列挙。
findを使って以下のようにかける。
find . -type d -name "include" -prune -o -name "*.h" -print
列挙したファイルのファイル名とカレントディレクトリからの相対パスはbasename
とdirname
で得られる。
#!/bin/sh FILEPATHS=`find . -type d -name "include" -prune -o -name "*.h" -print` for filepath in $FILEPATHS; do BASEPATH=`basename $filepath` DIRNAME=`dirname $filepath` echo $BASEPATH echo $DIRNAME done
参考
boost::bindとboost::functionをメンバ関数に使う
タイトル通り。
boost::bind
はメンバ関数を指定すると、第一引数にクラスを引数に取る関数として解釈される。
例
#include <iostream> #include <boost/function.hpp> #include <boost/bind.hpp> struct LinearExtrapolation { LinearExtrapolation( const double leftPoint, const double leftValue, const double rightPoint, const double rightValue) : _leftPoint(leftPoint), _leftValue(leftValue), _slope((rightValue - leftValue) / (rightPoint - leftPoint)){} ~LinearExtrapolation(){}; //! linear extrapolation. double operator() (const double x) const { return (x - _leftPoint) * _slope + _leftValue; } //! differentail of operator() double differential(const double x) const { return x * _slope; } private: const double _leftPoint; const double _leftValue; const double _slope; }; /** * @brief Functor example. */ struct Functor1 { double operator() ( const double time, const double state, const LinearExtrapolation& extrapolation) const { return time * extrapolation(state); } }; /** * @brief differetinal of Functor1 w.r.t. state variable. */ struct Functor2 { double operator() ( const double time, const double state, const LinearExtrapolation& extrapolation) const { return time * extrapolation.differential(state); } }; int main(int argc, char const* argv[]) { LinearExtrapolation extrapolation(-10.0, -20.0, 10.0, 20.0); Functor1 functor1; Functor2 functor2; boost::function<double (double, double)> function1 = boost::bind(&Functor1::operator(), &functor1, _1, _2, extrapolation); boost::function<double (double, double)> function2 = boost::bind(&Functor2::operator(), &functor2, _1, _2, extrapolation); std::cout << function1(1.0, 0.0) << std::endl;//output 0 std::cout << function2(1.0, 2.0) << std::endl;//output 4 return 0; }