- http://d.hatena.ne.jp/conceal-rs/20081220/1229764452
- http://d.hatena.ne.jp/conceal-rs/20081218/1229609673
普通に C で書いた処理をうまく繋げられるのが,いい感じですね.
##配列を操作する 配列内の数値をすべて掛け合わせるような処理を実装する.
###処理実体 配列とその長さを受け取って,配列内の値を順に掛け算していく.
- mul_all.c
float mul_all(array, nx)
float array[];
int nx;
{
float result = 1.0;
int i;
for(i=0; i<nx; i++){
result = result * array[i];
}
return(result);
}
これを検証するためのコード.
- main.c
#include <stdio.h>
float mul_all(float array[], int nx);
int main()
{
int n = 5;
float a[n];
int i;
for(i=0; i<n; i++){
a[i] = i + 1;
printf("%f\n", a[i]);
}
printf("mul_all()=%f\n", mul_all(a, n));
}
% cc -o mul_all mul_all.c main.c
% ./mul_all
1.000000
2.000000
3.000000
4.000000
5.000000
mul_all()=120.000000
###C と Ruby の接続 そしてラッパーです.今回は NArray を使うそうなので,そのインストール.
% sudo gem install narray
ラッパーの記述
- test3.c
#include "ruby.h"
#include "narray.h"
float mul_all(float array[], int nx);
VALUE wrap_mul_all(self, na)
VALUE self, na;
{
VALUE na2;
struct NARRAY *n_na;
float result;
na2 = na_cast_object(na, NA_SFLOAT);
GetNArray(na2,n_na);
result = mul_all((float*)n_na->ptr, n_na->total);
return( rb_float_new(result) );
}
void Init_test()
{
VALUE module;
rb_require("narray");
module = rb_define_module("Test");
rb_define_module_function(module, "mul_all", wrap_mul_all, 1);
}
wrap_mul_all の流れとしては,
- Ruby からやってきた VALUE 型構造体(na)を,NArray オブジェクト(na2)へ cast する (na_cast_object)
- それ(na)が NArray オブジェクトであれば,データ実体(NARRAY)へのポインタ(n_na)を返す(GetNArray)
- mul_all は float 型の配列を受け取り((float*)n_na->ptr),計算する
- 計算結果を Ruby の FLOAT 型に変換して返す (rb_float_new)
な感じかな?もうちょい C を勉強し直さないとダメだなorz.
###コンパイルと実行 今回は外部ファイルが必要なので,その記述も含めて extconf.rb を書きます.
- extconf.rb
require 'mkmf'
dir_config('narray', $sitearcchdir, $sitearcchdir)
if !(have_header('narray.h') and have_header('narray_config.h'))
print <<-EOS
** configure error **
Header narray.h or narray_config.h is not found. If you have these files in /narraydir/include, try the following:
% ruby extconf.rb --with-narray-include=/narraydir/include
EOS
exit -1
end
if /cygwin|mingw/ =~ RUBY_PLATFORM
unless have_library('narray')
print <<-EOS
** configure error **
libnarray.a is not found.
% ruby extconf.rb --with-narray-lib=/narraydir/lib
EOS
exit -1
end
end
create_makefile('test')
そしてコンパイルと実行
% ruby extconf.rb --with-narray-include=/var/lib/gems/1.8/gems/narray-0.5.9.6
% make
% irb
>> require 'narray'
=> true
>> require 'test'
=> true
>> a = NArray.sfloat(5).indgen!(1,1)
=> NArraysfloat5:
[ 1.0, 2.0, 3.0, 4.0, 5.0 ]
>> Test.mul_all(a)
=> 120.0
###NArray へのメソッド追加 次は Ruby らしく,NArray#mul_all として追加してみることに.
- test4.c
#include "ruby.h"
#include "narray.h"
float mul_all(float array[], int nx);
VALUE wrap_mul_all(self)
VALUE self;
{
VALUE na2;
struct NARRAY *n_na;
float result;
na2 = na_cast_object(self, NA_SFLOAT);
GetNArray(na2, n_na);
result = mul_all((float*)n_na->ptr, n_na->total);
return( rb_float_new(result) );
}
void Init_test()
{
VALUE class_na;
rb_require("narray");
class_na = rb_const_get(rb_cObject, rb_intern("NArray"));
rb_define_method(class_na, "mul_all", wrap_mul_all, 0);
}
基本的にさっきと同じようだが,
- メソッドが実行されている VALUE 型構造体(self)を,NArray オブジェクト(na2)へ cast する (na_cast_object)
と
- NArray クラスを取得する (rb_const_get)
- NArray クラス(class_na) に mul_all メソッドを追加する (rb_define_method)
と言う点が異なる.
そしてコンパイルと実行.
% mv test3.c test3.c.org
% ruby extconf.rb --with-narray-include=/var/lib/gems/1.8/gems/narray-0.5.9.6
% make
% irb
>> require 'narray'
=> true
>> require 'test'
=> true
>> NArray.sfloat(5).indgen!(1,1).mul_all
=> 120.0
>>
何となく流れはわかったんだけど,もっと C の知識が必要だなーと,ちょっと凹んだ・・・・
comments powered by Disqus