フィボナッチ数列
デバッグとチューニングのお話の前に、おさらいを兼ねてフィボナッチ数列の第n項:fib(n)を求めるサンプルを書いてみましょうか。フィボナッチ数列:0,1,1,2,3,5,8...の第n項:fib(n)は、以下のように再帰的に定義されます。
fib(0) = 0 fib(1) = 1 fib(n) = fib(n-1) + fib(n-2) if n > 1
この定義に忠実にCnCで実装します。上記の定義をそのままstep内で求め、得られた結果をn番目のitemに出力するとしましょう。step内の処理は:
switch ( n ) {
case 0: itemのn番目に 0 をputする
case 1: itemのn番目に 1 をputする
default:
itemのn-1番目をgetする
itemのn-2番目をgetする
ふたつを加えてitemのn番目にputする
}
となります。このstepを0,1,...nで着火すればitemのn番目にfib(n)が求まります。
CnCのチュートリアルには、こんなコードが示されていました。
// 実害のない warning を抑止する
#define _CRT_SECURE_NO_DEPRECATE
#include <cnc/cnc.h>
#include <cnc/debug.h> // デバッグのために追加
// フィボナッチ数 に十分な大きさの型
typedef unsigned long long fib_type;
// forward declaration
struct fib_context;
// フィボナッチ数を求める step
struct fib_step {
// declaration of execute method goes here
int execute( const int & tag, fib_context & c ) const;
};
// コンテキスト: tag/step/itemの集合およびそれらの依存関係を束ねる
struct fib_context : public CnC::context< fib_context > {
CnC::step_collection< fib_step > m_steps;
CnC::item_collection< int, fib_type > m_fibs;
CnC::tag_collection< int > m_tags;
// コンストラクタ
fib_context();
};
fib_context::fib_context()
: CnC::context< fib_context >(),
m_steps( *this ),
m_fibs( *this ),
m_tags( *this ) {
m_tags.prescribes( m_steps, *this ); // m_tags は m_step に指示する
m_steps.consumes( m_fibs ); // m_steps は m_fibs を消費する
m_steps.produces( m_fibs ); // m_steps は m_fibs を生産する
}
// フィボナッチ数列の第tag項を求める
int fib_step::execute( const int & tag, fib_context & ctxt ) const {
switch ( tag ) {
case 0 : // fib(0) = 0
ctxt.m_fibs.put( tag, 0 ); break;
case 1 : // fib(1) = 1
ctxt.m_fibs.put( tag, 1 ); break;
default : // fib(n) = fib(n-1) + fib(n-2)
// 前の二つを手に入れて
fib_type f_1; ctxt.m_fibs.get( tag - 1, f_1 );
fib_type f_2; ctxt.m_fibs.get( tag - 2, f_2 );
// 加えたものが結果となる
ctxt.m_fibs.put( tag, f_1 + f_2 );
}
return CnC::CNC_Success;
}
int main( int argc, char* argv[] ) {
int n = 42;
// eval command line args
if ( argc < 2 ) {
std::cerr << "usage: " << argv[0] << " n\nUsing default value " << n << std::endl;
} else {
n = atol( argv[1] );
}
// コンテキストを生成し
fib_context ctxt;
// tagをputして
for( int i = 0; i <= n; ++i ) ctxt.m_tags.put( i );
// 終了を待ち
ctxt.wait();
// 結果を取得して
fib_type res2;
ctxt.m_fibs.get( n, res2 );
// 出力する
std::cout << "fib (" << n << "): " << res2 << std::endl;
return 0;
}

