2013-11-04 24 views
3

我正在研究Ruby原生C方法:power mod。這是我得到的:Ruby原生C大整數段錯誤

#define TO_BIGNUM(x) (FIXNUM_P(x) ? rb_int2big(FIX2LONG(x)) : x) 
#define CONST2BIGNUM(x) (TO_BIGNUM(INT2NUM(x))) 

VALUE method_big_power_mod(VALUE self, VALUE base, VALUE exp, VALUE mod){ 
    VALUE res = TO_BIGNUM(INT2NUM(1)); 

    base = TO_BIGNUM(base); 
    exp = TO_BIGNUM(exp); 
    mod = TO_BIGNUM(mod); 

    while (rb_big_cmp(exp, CONST2BIGNUM(0))) { 
    if (rb_big_modulo(exp, CONST2BIGNUM(2))) { 
     VALUE mul = rb_big_mul(res, base); 
     res = rb_big_modulo(mul, mod); 
    } 
    base = rb_big_modulo(rb_big_pow(base, CONST2BIGNUM(2)), mod); 
    exp = rb_big_div(exp, CONST2BIGNUM(2)); 
    } 

    return res; 
} 

它每次都會發生段錯誤。我將問題隔離爲rb_big_modulo調用。 gdb stacktrace說在調用rb_big_modulo之後,它在bigdivrem方法中崩潰。我試圖通過bignum.c的來源,但我無法弄清楚是什麼導致了這次事故。難道我做錯了什麼?

+0

你可以添加足夠的代碼使它成爲[SSCCE](http://sscce.org/)嗎? – n0741337

回答

1

但是也有一些導致段錯誤兩個問題:

1 - 功能rb_big_*有時不返回Bignum對象,但當你叫那麼第一個參數必須Bignum對象。例如:

if (rb_big_modulo(exp, CONST2BIGNUM(2))) { 
    VALUE mul = rb_big_mul(res, base); // This maybe return a Fixnum 
    res = rb_big_modulo(mul, mod); // This will cause a segfault :(
} 

2 - 功能rb_big_pow當你既ARGS Bignum調用它,它會發出警告,並會返回一個Float對象,你不能輕易地轉換爲Bignum對象。所以,你應該更換,你把它用線:

VALUE x = TO_BIGNUM(rb_big_pow(base, INT2NUM(2))); // Power by a Fixnum instead a Bignum 
base = TO_BIGNUM(rb_big_modulo(x , mod)); 

最終的實施將是:

#define TO_BIGNUM(x) (FIXNUM_P(x) ? rb_int2big(FIX2LONG(x)) : x) 
#define CONST2BIGNUM(x) (TO_BIGNUM(INT2NUM(x))) 

VALUE method_big_power_mod(VALUE self, VALUE base, VALUE exp, VALUE mod){ 
    VALUE res = TO_BIGNUM(INT2NUM(1)); 

    base = TO_BIGNUM(base); 
    exp = TO_BIGNUM(exp); 
    mod = TO_BIGNUM(mod); 

    while (rb_big_cmp(exp, CONST2BIGNUM(0))) { 
    if (rb_big_modulo(exp, CONST2BIGNUM(2))) { 
     VALUE mul = TO_BIGNUM(rb_big_mul(res, base)); 
     res = TO_BIGNUM(rb_big_modulo(mul, mod)); 
    } 
    VALUE x = TO_BIGNUM(rb_big_pow(base, INT2NUM(2))); 

    base = TO_BIGNUM(rb_big_modulo(x , mod)); 
    exp = TO_BIGNUM(rb_big_div(exp, CONST2BIGNUM(2))); 
    } 

    return res; 
} 

我不知道所有這些轉換的性能影響。也許,您應該測試它是Fixnum還是Bignum,並使用適當的函數或基準測試兩種方法進行計算。

當我跑了它,我想到了一個無限循環,但我不知道我是否用正確的值調用它。