3

Ruby に配列があり、それらを .normalize メソッドで拡張したいと考えています。このメソッドは、すべての要素の合計が 1 になるように配列を変更する必要があります。これは Ruby ではコストがかかりすぎるため、RubyInline を使用して C で実行したいと考えています。

require "rubygems"
require "inline"

class Array
inline do |builder|
    builder.c_raw '
     static VALUE normalize(VALUE self) {
        double total_size = 0, len;
        int i;

        VALUE* array = RARRAY_PTR(self);
        len = RARRAY_LEN(self);

        for(i=0; i < len; i++){
            total_size += NUM2DBL(array[i]);
        }

        for(i=0; i < len; i++){
            array[i] = INT2NUM(NUM2DBL(array[i])/total_size);
        }

        return array;
    }'
  end
end

a = [1,2,0,0,0,0,0,3,0,4]

puts a.normalize.inspect

これにより、

$ ruby tmp.rb 
tmp.rb:29: [BUG] Segmentation fault
ruby 1.8.7 (2011-06-30 patchlevel 352) [x86_64-linux]

Aborted (core dumped)

編集:いくつかのデバッグの後、クラッシュが発生したようです

VALUE* array = RARRAY_PTR(self);
4

1 に答える 1

3

ここで修正すべき点がいくつかあります。

rubyinlineを使用するc_rawと、アリティを検出しようとせず、代わりに可変数の引数を使用することを想定します。これをオーバーライドする (:arity => 0 を渡す) か、メソッドのシグネチャを次のように変更できます。

VALUE normalize(int argc, VALUE *argv, VALUE self)

現時点では、rubyinline はメソッドにそのシグネチャがあると想定しているため、整数 0 をポインターとして再解釈している可能性があります。

次に、すべての配列要素が < 1 であるため、現時点では常に配列をゼロで埋めています。その後、整数に変換しているため、0 を取得します。 rb_float_newdouble を ruby​​ に戻すために使用しますFloat

最後に、戻り値が間違っています。 aVALUE *ではなく aVALUEです。おそらく代わりに戻りたいでしょうself

最後に、自分のメソッドを呼び出す方がより Ruby らしくなりますnormalize!。デフォルトでは、Ruby inline は c 関数名からメソッド名を抽出します。もちろん、そのような感嘆符を使用することはできません。オプションで上書きできますmethod_name

全体として、あなたの例の私のバージョンは次のようになります

require "rubygems"
require "inline"

class Array
  inline do |builder|
    builder.c_raw <<-'SRC', :method_name => 'normalize!', :arity => 0
     static VALUE normalize(VALUE self) {
        double total_size = 0;
        size_t len, i;

        VALUE* array = RARRAY_PTR(self);
        len = RARRAY_LEN(self);

        for(i=0; i < len; i++){
            total_size += NUM2DBL(array[i]);
        }
        for(i=0; i < len; i++){
            array[i] = rb_float_new((NUM2DBL(array[i])/total_size));
        }

        return self;
    }
    SRC
  end
end

a = [1,2,0,0,0,0,0,1,0,4]

puts a.normalize!.inspect
于 2012-12-31T18:08:32.337 に答える