Feature #12484 » 0002-optimize-Rational-methods.patch
| rational.c | ||
|---|---|---|
| #define GMP_GCD_DIGITS 1 | ||
| #define INT_POSITIVE_P(x) (FIXNUM_P(x) ? ((SIGNED_VALUE)(x) > (SIGNED_VALUE)INT2FIX(0)) : BIGNUM_POSITIVE_P(x)) | ||
| #define INT_NEGATIVE_P(x) (FIXNUM_P(x) ? ((SIGNED_VALUE)(x) < 0) : BIGNUM_NEGATIVE_P(x)) | ||
| #define INT_ZERO_P(x) (FIXNUM_P(x) ? (FIX2LONG(x) == 0) : rb_bigzero_p(x)) | ||
| VALUE rb_cRational; | ||
| static ID id_abs, id_cmp, id_convert, id_eqeq_p, id_expt, id_fdiv, | ||
| id_idiv, id_integer_p, id_negate, id_to_f, | ||
| id_to_i, id_truncate, id_i_num, id_i_den; | ||
| static ID id_abs, id_eqeq_p, id_idiv, id_integer_p, id_negate, id_to_i, | ||
| id_i_num, id_i_den; | ||
| #define f_boolcast(x) ((x) ? Qtrue : Qfalse) | ||
| #define f_inspect rb_inspect | ||
| ... | ... | |
| } | ||
| inline static VALUE | ||
| f_cmp(VALUE x, VALUE y) | ||
| { | ||
| if (FIXNUM_P(x) && FIXNUM_P(y)) { | ||
| long c = FIX2LONG(x) - FIX2LONG(y); | ||
| if (c > 0) | ||
| c = 1; | ||
| else if (c < 0) | ||
| c = -1; | ||
| return INT2FIX(c); | ||
| } | ||
| return rb_funcall(x, id_cmp, 1, y); | ||
| } | ||
| inline static VALUE | ||
| f_div(VALUE x, VALUE y) | ||
| { | ||
| if (FIXNUM_P(y) && FIX2LONG(y) == 1) | ||
| return x; | ||
| if (FIXNUM_P(x) || RB_TYPE_P(x, T_BIGNUM)) | ||
| return rb_int_div(x, y); | ||
| return rb_funcall(x, '/', 1, y); | ||
| } | ||
| ... | ... | |
| } | ||
| else if (ix == 1) | ||
| return y; | ||
| return rb_int_mul(x, y); | ||
| } | ||
| else if (RB_TYPE_P(x, T_BIGNUM)) | ||
| return rb_int_mul(x, y); | ||
| return rb_funcall(x, '*', 1, y); | ||
| } | ||
| ... | ... | |
| return rb_funcall(x, '-', 1, y); | ||
| } | ||
| fun1(abs) | ||
| inline static VALUE | ||
| f_abs(VALUE x) | ||
| { | ||
| if (FIXNUM_P(x) || RB_TYPE_P(x, T_BIGNUM)) | ||
| return rb_int_abs(x); | ||
| return rb_funcall(x, id_abs, 0); | ||
| } | ||
| fun1(integer_p) | ||
| fun1(negate) | ||
| ... | ... | |
| return rb_str_to_inum(x, 10, 0); | ||
| return rb_funcall(x, id_to_i, 0); | ||
| } | ||
| inline static VALUE | ||
| f_to_f(VALUE x) | ||
| { | ||
| if (RB_TYPE_P(x, T_STRING)) | ||
| return DBL2NUM(rb_str_to_dbl(x, 0)); | ||
| return rb_funcall(x, id_to_f, 0); | ||
| } | ||
| inline static VALUE | ||
| f_eqeq_p(VALUE x, VALUE y) | ||
| ... | ... | |
| return rb_funcall(x, id_eqeq_p, 1, y); | ||
| } | ||
| fun2(expt) | ||
| fun2(fdiv) | ||
| fun2(idiv) | ||
| #define f_expt10(x) f_expt(INT2FIX(10), x) | ||
| inline static VALUE | ||
| f_negative_p(VALUE x) | ||
| { | ||
| if (FIXNUM_P(x)) | ||
| return f_boolcast(FIX2LONG(x) < 0); | ||
| return rb_funcall(x, '<', 1, ZERO); | ||
| } | ||
| #define f_positive_p(x) (!f_negative_p(x)) | ||
| #define f_expt10(x) rb_int_pow(INT2FIX(10), x) | ||
| inline static VALUE | ||
| f_zero_p(VALUE x) | ||
| ... | ... | |
| if (FIXNUM_P(x) && FIXNUM_P(y)) | ||
| return LONG2NUM(i_gcd(FIX2LONG(x), FIX2LONG(y))); | ||
| if (f_negative_p(x)) | ||
| x = f_negate(x); | ||
| if (f_negative_p(y)) | ||
| y = f_negate(y); | ||
| if (INT_NEGATIVE_P(x)) | ||
| x = rb_int_uminus(x); | ||
| if (INT_NEGATIVE_P(y)) | ||
| y = rb_int_uminus(y); | ||
| if (f_zero_p(x)) | ||
| if (INT_ZERO_P(x)) | ||
| return y; | ||
| if (f_zero_p(y)) | ||
| if (INT_ZERO_P(y)) | ||
| return x; | ||
| for (;;) { | ||
| ... | ... | |
| return LONG2NUM(i_gcd(FIX2LONG(x), FIX2LONG(y))); | ||
| } | ||
| z = x; | ||
| x = f_mod(y, x); | ||
| x = rb_int_modulo(y, x); | ||
| y = z; | ||
| } | ||
| /* NOTREACHED */ | ||
| ... | ... | |
| inline static VALUE | ||
| f_lcm(VALUE x, VALUE y) | ||
| { | ||
| if (f_zero_p(x) || f_zero_p(y)) | ||
| if (INT_ZERO_P(x) || INT_ZERO_P(y)) | ||
| return ZERO; | ||
| return f_abs(f_mul(f_div(x, f_gcd(x, y)), y)); | ||
| } | ||
| ... | ... | |
| return nurat_s_new_internal(klass, ZERO, ONE); | ||
| } | ||
| #define rb_raise_zerodiv() rb_raise(rb_eZeroDivError, "divided by 0") | ||
| #if 0 | ||
| static VALUE | ||
| nurat_s_new_bang(int argc, VALUE *argv, VALUE klass) | ||
| ... | ... | |
| if (!k_integer_p(den)) | ||
| den = f_to_i(den); | ||
| switch (FIX2INT(f_cmp(den, ZERO))) { | ||
| switch (FIX2INT(rb_int_cmp(den, ZERO))) { | ||
| case -1: | ||
| num = f_negate(num); | ||
| den = f_negate(den); | ||
| break; | ||
| case 0: | ||
| rb_raise_zerodiv(); | ||
| rb_num_zerodiv(); | ||
| break; | ||
| } | ||
| break; | ||
| ... | ... | |
| { | ||
| VALUE gcd; | ||
| switch (FIX2INT(f_cmp(den, ZERO))) { | ||
| switch (FIX2INT(rb_int_cmp(den, ZERO))) { | ||
| case -1: | ||
| num = f_negate(num); | ||
| den = f_negate(den); | ||
| break; | ||
| case 0: | ||
| rb_raise_zerodiv(); | ||
| rb_num_zerodiv(); | ||
| break; | ||
| } | ||
| ... | ... | |
| inline static VALUE | ||
| nurat_s_canonicalize_internal_no_reduce(VALUE klass, VALUE num, VALUE den) | ||
| { | ||
| switch (FIX2INT(f_cmp(den, ZERO))) { | ||
| switch (FIX2INT(rb_int_cmp(den, ZERO))) { | ||
| case -1: | ||
| num = f_negate(num); | ||
| den = f_negate(den); | ||
| break; | ||
| case 0: | ||
| rb_raise_zerodiv(); | ||
| rb_num_zerodiv(); | ||
| break; | ||
| } | ||
| ... | ... | |
| return nurat_s_canonicalize_internal_no_reduce(klass, x, y); | ||
| } | ||
| static VALUE nurat_s_convert(int argc, VALUE *argv, VALUE klass); | ||
| /* | ||
| * call-seq: | ||
| * Rational(x[, y]) -> numeric | ||
| ... | ... | |
| static VALUE | ||
| nurat_f_rational(int argc, VALUE *argv, VALUE klass) | ||
| { | ||
| return rb_funcall2(rb_cRational, id_convert, argc, argv); | ||
| return nurat_s_convert(argc, argv, rb_cRational); | ||
| } | ||
| /* | ||
| ... | ... | |
| return dat->den; | ||
| } | ||
| /* | ||
| * call-seq: | ||
| * -rat -> rational | ||
| * | ||
| * Negates +rat+. | ||
| */ | ||
| static VALUE | ||
| nurat_negate(VALUE self) | ||
| { | ||
| get_dat1(self); | ||
| return f_rational_new2(CLASS_OF(self), rb_int_uminus(dat->num), dat->den); | ||
| } | ||
| #ifndef NDEBUG | ||
| #define f_imul f_imul_orig | ||
| #endif | ||
| ... | ... | |
| VALUE c; | ||
| if (k == '+') | ||
| c = f_add(a, b); | ||
| c = rb_int_plus(a, b); | ||
| else | ||
| c = f_sub(a, b); | ||
| c = rb_int_minus(a, b); | ||
| b = f_idiv(aden, g); | ||
| b = rb_int_idiv(aden, g); | ||
| g = f_gcd(c, g); | ||
| num = f_idiv(c, g); | ||
| a = f_idiv(bden, g); | ||
| den = f_mul(a, b); | ||
| num = rb_int_idiv(c, g); | ||
| a = rb_int_idiv(bden, g); | ||
| den = rb_int_mul(a, b); | ||
| } | ||
| else { | ||
| VALUE g = f_gcd(aden, bden); | ||
| VALUE a = f_mul(anum, f_idiv(bden, g)); | ||
| VALUE b = f_mul(bnum, f_idiv(aden, g)); | ||
| VALUE a = rb_int_mul(anum, rb_int_idiv(bden, g)); | ||
| VALUE b = rb_int_mul(bnum, rb_int_idiv(aden, g)); | ||
| VALUE c; | ||
| if (k == '+') | ||
| c = f_add(a, b); | ||
| c = rb_int_plus(a, b); | ||
| else | ||
| c = f_sub(a, b); | ||
| c = rb_int_minus(a, b); | ||
| b = f_idiv(aden, g); | ||
| b = rb_int_idiv(aden, g); | ||
| g = f_gcd(c, g); | ||
| num = f_idiv(c, g); | ||
| a = f_idiv(bden, g); | ||
| den = f_mul(a, b); | ||
| num = rb_int_idiv(c, g); | ||
| a = rb_int_idiv(bden, g); | ||
| den = rb_int_mul(a, b); | ||
| } | ||
| return f_rational_new_no_reduce2(CLASS_OF(self), num, den); | ||
| } | ||
| static VALUE nurat_to_f(VALUE self); | ||
| /* | ||
| * call-seq: | ||
| * rat + numeric -> numeric | ||
| ... | ... | |
| { | ||
| get_dat1(self); | ||
| return f_addsub(self, | ||
| dat->num, dat->den, | ||
| other, ONE, '+'); | ||
| return f_rational_new_no_reduce2(CLASS_OF(self), | ||
| rb_int_plus(dat->num, rb_int_mul(other, dat->den)), | ||
| dat->den); | ||
| } | ||
| } | ||
| else if (RB_TYPE_P(other, T_FLOAT)) { | ||
| return f_add(f_to_f(self), other); | ||
| return DBL2NUM(RFLOAT_VALUE(nurat_to_f(self)) + RFLOAT_VALUE(other)); | ||
| } | ||
| else if (RB_TYPE_P(other, T_RATIONAL)) { | ||
| { | ||
| ... | ... | |
| { | ||
| get_dat1(self); | ||
| return f_addsub(self, | ||
| dat->num, dat->den, | ||
| other, ONE, '-'); | ||
| return f_rational_new_no_reduce2(CLASS_OF(self), | ||
| rb_int_minus(dat->num, rb_int_mul(other, dat->den)), | ||
| dat->den); | ||
| } | ||
| } | ||
| else if (RB_TYPE_P(other, T_FLOAT)) { | ||
| return f_sub(f_to_f(self), other); | ||
| return DBL2NUM(RFLOAT_VALUE(nurat_to_f(self)) - RFLOAT_VALUE(other)); | ||
| } | ||
| else if (RB_TYPE_P(other, T_RATIONAL)) { | ||
| { | ||
| ... | ... | |
| if (k == '/') { | ||
| VALUE t; | ||
| if (f_negative_p(bnum)) { | ||
| anum = f_negate(anum); | ||
| bnum = f_negate(bnum); | ||
| if (INT_NEGATIVE_P(bnum)) { | ||
| anum = rb_int_uminus(anum); | ||
| bnum = rb_int_uminus(bnum); | ||
| } | ||
| t = bnum; | ||
| bnum = bden; | ||
| ... | ... | |
| VALUE g1 = f_gcd(anum, bden); | ||
| VALUE g2 = f_gcd(aden, bnum); | ||
| num = f_mul(f_idiv(anum, g1), f_idiv(bnum, g2)); | ||
| den = f_mul(f_idiv(aden, g2), f_idiv(bden, g1)); | ||
| num = rb_int_mul(rb_int_idiv(anum, g1), rb_int_idiv(bnum, g2)); | ||
| den = rb_int_mul(rb_int_idiv(aden, g2), rb_int_idiv(bden, g1)); | ||
| } | ||
| return f_rational_new_no_reduce2(CLASS_OF(self), num, den); | ||
| } | ||
| ... | ... | |
| } | ||
| } | ||
| else if (RB_TYPE_P(other, T_FLOAT)) { | ||
| return f_mul(f_to_f(self), other); | ||
| return DBL2NUM(RFLOAT_VALUE(nurat_to_f(self)) * RFLOAT_VALUE(other)); | ||
| } | ||
| else if (RB_TYPE_P(other, T_RATIONAL)) { | ||
| { | ||
| ... | ... | |
| { | ||
| if (RB_TYPE_P(other, T_FIXNUM) || RB_TYPE_P(other, T_BIGNUM)) { | ||
| if (f_zero_p(other)) | ||
| rb_raise_zerodiv(); | ||
| rb_num_zerodiv(); | ||
| { | ||
| get_dat1(self); | ||
| ... | ... | |
| } | ||
| } | ||
| else if (RB_TYPE_P(other, T_FLOAT)) | ||
| return rb_funcall(f_to_f(self), '/', 1, other); | ||
| return DBL2NUM(RFLOAT_VALUE(nurat_to_f(self)) / RFLOAT_VALUE(other)); | ||
| else if (RB_TYPE_P(other, T_RATIONAL)) { | ||
| if (f_zero_p(other)) | ||
| rb_raise_zerodiv(); | ||
| rb_num_zerodiv(); | ||
| { | ||
| get_dat2(self, other); | ||
| ... | ... | |
| static VALUE | ||
| nurat_fdiv(VALUE self, VALUE other) | ||
| { | ||
| VALUE div; | ||
| if (f_zero_p(other)) | ||
| return f_div(self, f_to_f(other)); | ||
| return f_to_f(f_div(self, other)); | ||
| return DBL2NUM(RFLOAT_VALUE(nurat_to_f(self)) / 0.0); | ||
| if (FIXNUM_P(other) && FIX2LONG(other) == 1) | ||
| return nurat_to_f(self); | ||
| div = nurat_div(self, other); | ||
| if (RB_TYPE_P(div, T_RATIONAL)) | ||
| return nurat_to_f(div); | ||
| if (RB_TYPE_P(div, T_FLOAT)) | ||
| return div; | ||
| return rb_funcall(div, rb_intern("to_f"), 0); | ||
| } | ||
| inline static VALUE | ||
| ... | ... | |
| return f_rational_new_bang1(CLASS_OF(self), INT2FIX(f_odd_p(other) ? -1 : 1)); | ||
| } | ||
| else if (f_zero_p(dat->num)) { | ||
| if (FIX2INT(f_cmp(other, ZERO)) == -1) { | ||
| rb_raise_zerodiv(); | ||
| if (FIX2INT(rb_int_cmp(ZERO, other)) == 1) { | ||
| rb_num_zerodiv(); | ||
| } | ||
| else { | ||
| return f_rational_new_bang1(CLASS_OF(self), ZERO); | ||
| ... | ... | |
| get_dat1(self); | ||
| switch (FIX2INT(f_cmp(other, ZERO))) { | ||
| switch (FIX2INT(rb_int_cmp(other, ZERO))) { | ||
| case 1: | ||
| num = f_expt(dat->num, other); | ||
| den = f_expt(dat->den, other); | ||
| num = rb_int_pow(dat->num, other); | ||
| den = rb_int_pow(dat->den, other); | ||
| break; | ||
| case -1: | ||
| num = f_expt(dat->den, f_negate(other)); | ||
| den = f_expt(dat->num, f_negate(other)); | ||
| num = rb_int_pow(dat->den, rb_int_uminus(other)); | ||
| den = rb_int_pow(dat->num, rb_int_uminus(other)); | ||
| break; | ||
| default: | ||
| num = ONE; | ||
| ... | ... | |
| } | ||
| else if (RB_TYPE_P(other, T_BIGNUM)) { | ||
| rb_warn("in a**b, b may be too big"); | ||
| return f_expt(f_to_f(self), other); | ||
| return rb_float_pow(nurat_to_f(self), other); | ||
| } | ||
| else if (RB_TYPE_P(other, T_FLOAT) || RB_TYPE_P(other, T_RATIONAL)) { | ||
| return f_expt(f_to_f(self), other); | ||
| return rb_float_pow(nurat_to_f(self), other); | ||
| } | ||
| else { | ||
| return rb_num_coerce_bin(self, other, id_expt); | ||
| return rb_num_coerce_bin(self, other, rb_intern("**")); | ||
| } | ||
| } | ||
| ... | ... | |
| get_dat1(self); | ||
| if (FIXNUM_P(dat->den) && FIX2LONG(dat->den) == 1) | ||
| return f_cmp(dat->num, other); /* c14n */ | ||
| return f_cmp(self, f_rational_new_bang1(CLASS_OF(self), other)); | ||
| return rb_int_cmp(dat->num, other); /* c14n */ | ||
| other = f_rational_new_bang1(CLASS_OF(self), other); | ||
| } | ||
| } | ||
| else if (RB_TYPE_P(other, T_FLOAT)) { | ||
| return f_cmp(f_to_f(self), other); | ||
| if (RB_TYPE_P(other, T_FLOAT)) { | ||
| return rb_dbl_cmp(RFLOAT_VALUE(nurat_to_f(self)), RFLOAT_VALUE(other)); | ||
| } | ||
| else if (RB_TYPE_P(other, T_RATIONAL)) { | ||
| { | ||
| ... | ... | |
| num2 = f_imul(FIX2LONG(bdat->num), FIX2LONG(adat->den)); | ||
| } | ||
| else { | ||
| num1 = f_mul(adat->num, bdat->den); | ||
| num2 = f_mul(bdat->num, adat->den); | ||
| num1 = rb_int_mul(adat->num, bdat->den); | ||
| num2 = rb_int_mul(bdat->num, adat->den); | ||
| } | ||
| return f_cmp(f_sub(num1, num2), ZERO); | ||
| return rb_int_cmp(rb_int_minus(num1, num2), ZERO); | ||
| } | ||
| } | ||
| else { | ||
| return rb_num_coerce_cmp(self, other, id_cmp); | ||
| return rb_num_coerce_cmp(self, other, rb_intern("<=>")); | ||
| } | ||
| } | ||
| ... | ... | |
| { | ||
| get_dat1(self); | ||
| if (f_zero_p(dat->num) && f_zero_p(other)) | ||
| if (INT_ZERO_P(dat->num) && INT_ZERO_P(other)) | ||
| return Qtrue; | ||
| if (!FIXNUM_P(dat->den)) | ||
| return Qfalse; | ||
| if (FIX2LONG(dat->den) != 1) | ||
| return Qfalse; | ||
| if (f_eqeq_p(dat->num, other)) | ||
| return Qtrue; | ||
| return Qfalse; | ||
| return rb_int_equal(dat->num, other); | ||
| } | ||
| } | ||
| else if (RB_TYPE_P(other, T_FLOAT)) { | ||
| return f_eqeq_p(f_to_f(self), other); | ||
| return f_boolcast(rb_dbl_cmp(RFLOAT_VALUE(nurat_to_f(self)), RFLOAT_VALUE(other)) | ||
| == INT2FIX(0)); | ||
| } | ||
| else if (RB_TYPE_P(other, T_RATIONAL)) { | ||
| { | ||
| get_dat2(self, other); | ||
| if (f_zero_p(adat->num) && f_zero_p(bdat->num)) | ||
| if (INT_ZERO_P(adat->num) && INT_ZERO_P(bdat->num)) | ||
| return Qtrue; | ||
| return f_boolcast(f_eqeq_p(adat->num, bdat->num) && | ||
| f_eqeq_p(adat->den, bdat->den)); | ||
| return f_boolcast(rb_int_equal(adat->num, bdat->num) && | ||
| rb_int_equal(adat->den, bdat->den)); | ||
| } | ||
| } | ||
| else { | ||
| ... | ... | |
| return rb_assoc_new(f_rational_new_bang1(CLASS_OF(self), other), self); | ||
| } | ||
| else if (RB_TYPE_P(other, T_FLOAT)) { | ||
| return rb_assoc_new(other, f_to_f(self)); | ||
| return rb_assoc_new(other, nurat_to_f(self)); | ||
| } | ||
| else if (RB_TYPE_P(other, T_RATIONAL)) { | ||
| return rb_assoc_new(other, self); | ||
| ... | ... | |
| } | ||
| #endif | ||
| /* | ||
| * call-seq: | ||
| * rat.positive? -> true or false | ||
| * | ||
| * Returns +true+ if +rat+ is greater than 0. | ||
| */ | ||
| static VALUE | ||
| nurat_positive_p(VALUE self) | ||
| { | ||
| get_dat1(self); | ||
| return f_boolcast(INT_POSITIVE_P(dat->num)); | ||
| } | ||
| /* | ||
| * call-seq: | ||
| * rat.negative? -> true or false | ||
| * | ||
| * Returns +true+ if +rat+ is less than 0. | ||
| */ | ||
| static VALUE | ||
| nurat_negative_p(VALUE self) | ||
| { | ||
| get_dat1(self); | ||
| return f_boolcast(INT_NEGATIVE_P(dat->num)); | ||
| } | ||
| static VALUE | ||
| nurat_floor(VALUE self) | ||
| { | ||
| get_dat1(self); | ||
| return f_idiv(dat->num, dat->den); | ||
| return rb_int_idiv(dat->num, dat->den); | ||
| } | ||
| static VALUE | ||
| nurat_ceil(VALUE self) | ||
| { | ||
| get_dat1(self); | ||
| return f_negate(f_idiv(f_negate(dat->num), dat->den)); | ||
| return rb_int_uminus(rb_int_idiv(rb_int_uminus(dat->num), dat->den)); | ||
| } | ||
| /* | ||
| ... | ... | |
| nurat_truncate(VALUE self) | ||
| { | ||
| get_dat1(self); | ||
| if (f_negative_p(dat->num)) | ||
| return f_negate(f_idiv(f_negate(dat->num), dat->den)); | ||
| return f_idiv(dat->num, dat->den); | ||
| if (INT_NEGATIVE_P(dat->num)) | ||
| return rb_int_uminus(rb_int_idiv(rb_int_uminus(dat->num), dat->den)); | ||
| return rb_int_idiv(dat->num, dat->den); | ||
| } | ||
| static VALUE | ||
| ... | ... | |
| num = dat->num; | ||
| den = dat->den; | ||
| neg = f_negative_p(num); | ||
| neg = INT_NEGATIVE_P(num); | ||
| if (neg) | ||
| num = f_negate(num); | ||
| num = rb_int_uminus(num); | ||
| num = f_add(f_mul(num, TWO), den); | ||
| den = f_mul(den, TWO); | ||
| num = f_idiv(num, den); | ||
| num = rb_int_plus(rb_int_mul(num, TWO), den); | ||
| den = rb_int_mul(den, TWO); | ||
| num = rb_int_idiv(num, den); | ||
| if (neg) | ||
| num = f_negate(num); | ||
| num = rb_int_uminus(num); | ||
| return num; | ||
| } | ||
| ... | ... | |
| rb_raise(rb_eTypeError, "not an integer"); | ||
| b = f_expt10(n); | ||
| s = f_mul(self, b); | ||
| s = nurat_mul(self, b); | ||
| if (k_float_p(s)) { | ||
| if (f_lt_p(n, ZERO)) | ||
| if (INT_NEGATIVE_P(n)) | ||
| return ZERO; | ||
| return self; | ||
| } | ||
| ... | ... | |
| s = (*func)(s); | ||
| s = f_div(f_rational_new_bang1(CLASS_OF(self), s), b); | ||
| s = nurat_div(f_rational_new_bang1(CLASS_OF(self), s), b); | ||
| if (f_lt_p(n, ONE)) | ||
| s = f_to_i(s); | ||
| if (RB_TYPE_P(s, T_RATIONAL) && FIX2INT(rb_int_cmp(n, ONE)) < 0) | ||
| s = nurat_truncate(s); | ||
| return s; | ||
| } | ||
| ... | ... | |
| nurat_to_f(VALUE self) | ||
| { | ||
| get_dat1(self); | ||
| return f_fdiv(dat->num, dat->den); | ||
| return rb_int_fdiv(dat->num, dat->den); | ||
| } | ||
| /* | ||
| ... | ... | |
| if (argc == 0) | ||
| return self; | ||
| if (f_negative_p(self)) | ||
| return f_negate(nurat_rationalize(argc, argv, f_abs(self))); | ||
| if (nurat_negative_p(self)) | ||
| return nurat_negate(nurat_rationalize(argc, argv, nurat_negate(self))); | ||
| rb_scan_args(argc, argv, "01", &e); | ||
| e = f_abs(e); | ||
| ... | ... | |
| if (RARRAY_LEN(a) != 2) | ||
| rb_raise(rb_eArgError, "marshaled rational must have an array whose length is 2 but %ld", RARRAY_LEN(a)); | ||
| if (f_zero_p(RARRAY_AREF(a, 1))) | ||
| rb_raise_zerodiv(); | ||
| rb_num_zerodiv(); | ||
| rb_ivar_set(self, id_i_num, RARRAY_AREF(a, 0)); | ||
| rb_ivar_set(self, id_i_den, RARRAY_AREF(a, 1)); | ||
| ... | ... | |
| return nurat_s_canonicalize_internal(rb_cRational, x, y); | ||
| } | ||
| static VALUE nurat_s_convert(int argc, VALUE *argv, VALUE klass); | ||
| VALUE | ||
| rb_Rational(VALUE x, VALUE y) | ||
| { | ||
| ... | ... | |
| numeric_quo(VALUE x, VALUE y) | ||
| { | ||
| if (RB_TYPE_P(y, T_FLOAT)) { | ||
| return f_fdiv(x, y); | ||
| return rb_funcall(x, rb_intern("fdiv"), 1, y); | ||
| } | ||
| #ifdef CANON | ||
| ... | ... | |
| { | ||
| x = rb_convert_type(x, T_RATIONAL, "Rational", "to_r"); | ||
| } | ||
| return rb_funcall(x, '/', 1, y); | ||
| return nurat_div(x, y); | ||
| } | ||
| ... | ... | |
| return INT2FIX(1); | ||
| } | ||
| static VALUE float_to_r(VALUE self); | ||
| /* | ||
| * call-seq: | ||
| * flo.numerator -> integer | ||
| ... | ... | |
| double d = RFLOAT_VALUE(self); | ||
| if (isinf(d) || isnan(d)) | ||
| return self; | ||
| return rb_call_super(0, 0); | ||
| return nurat_numerator(float_to_r(self)); | ||
| } | ||
| /* | ||
| ... | ... | |
| double d = RFLOAT_VALUE(self); | ||
| if (isinf(d) || isnan(d)) | ||
| return INT2FIX(1); | ||
| return rb_call_super(0, 0); | ||
| return nurat_denominator(float_to_r(self)); | ||
| } | ||
| /* | ||
| ... | ... | |
| } | ||
| #endif | ||
| #define id_lshift rb_intern("<<") | ||
| #define f_lshift(x,n) rb_funcall((x), id_lshift, 1, (n)) | ||
| /* | ||
| * call-seq: | ||
| * flt.to_r -> rational | ||
| ... | ... | |
| long ln = FIX2LONG(n); | ||
| if (ln == 0) | ||
| return f_to_r(f); | ||
| return rb_rational_new1(f); | ||
| if (ln > 0) | ||
| return f_to_r(f_lshift(f, n)); | ||
| return rb_rational_new1(rb_int_lshift(f, n)); | ||
| ln = -ln; | ||
| return rb_rational_new2(f, f_lshift(ONE, INT2FIX(ln))); | ||
| return rb_rational_new2(f, rb_int_lshift(ONE, INT2FIX(ln))); | ||
| } | ||
| #else | ||
| return f_to_r(f_mul(f, f_expt(INT2FIX(FLT_RADIX), n))); | ||
| f = rb_int_mul(f, rb_int_pow(INT2FIX(FLT_RADIX), n)); | ||
| if (RB_TYPE_P(f, T_RATIONAL)) | ||
| return f; | ||
| return rb_rational_new1(f); | ||
| #endif | ||
| } | ||
| ... | ... | |
| b = f_add(flt, e); | ||
| if (f_eqeq_p(a, b)) | ||
| return f_to_r(flt); | ||
| return float_to_r(flt); | ||
| nurat_rationalize_internal(a, b, &p, &q); | ||
| return rb_rational_new2(p, q); | ||
| ... | ... | |
| VALUE a, b, f, n, p, q; | ||
| float_decode_internal(flt, &f, &n); | ||
| if (f_zero_p(f) || f_positive_p(n)) | ||
| return rb_rational_new1(f_lshift(f, n)); | ||
| if (INT_ZERO_P(f) || FIX2INT(n) >= 0) | ||
| return rb_rational_new1(rb_int_lshift(f, n)); | ||
| #if FLT_RADIX == 2 | ||
| { | ||
| VALUE two_times_f, den; | ||
| two_times_f = f_mul(TWO, f); | ||
| den = f_lshift(ONE, f_sub(ONE, n)); | ||
| two_times_f = rb_int_mul(TWO, f); | ||
| den = rb_int_lshift(ONE, rb_int_minus(ONE, n)); | ||
| a = rb_rational_new2(f_sub(two_times_f, ONE), den); | ||
| b = rb_rational_new2(f_add(two_times_f, ONE), den); | ||
| a = rb_rational_new2(rb_int_minus(two_times_f, ONE), den); | ||
| b = rb_rational_new2(rb_int_plus(two_times_f, ONE), den); | ||
| } | ||
| #else | ||
| { | ||
| VALUE radix_times_f, den; | ||
| radix_times_f = f_mul(INT2FIX(FLT_RADIX), f); | ||
| den = f_expt(INT2FIX(FLT_RADIX), f_sub(ONE, n)); | ||
| radix_times_f = rb_int_mul(INT2FIX(FLT_RADIX), f); | ||
| den = rb_int_pow(INT2FIX(FLT_RADIX), rb_int_minus(ONE, n)); | ||
| a = rb_rational_new2(f_sub(radix_times_f, INT2FIX(FLT_RADIX - 1)), den); | ||
| b = rb_rational_new2(f_add(radix_times_f, INT2FIX(FLT_RADIX - 1)), den); | ||
| a = rb_rational_new2(rb_int_minus(radix_times_f, INT2FIX(FLT_RADIX - 1)), den); | ||
| b = rb_rational_new2(rb_int_plus(radix_times_f, INT2FIX(FLT_RADIX - 1)), den); | ||
| } | ||
| #endif | ||
| if (f_eqeq_p(a, b)) | ||
| return f_to_r(flt); | ||
| if (nurat_eqeq_p(a, b)) | ||
| return float_to_r(flt); | ||
| nurat_rationalize_internal(a, b, &p, &q); | ||
| return rb_rational_new2(p, q); | ||
| ... | ... | |
| float_rationalize(int argc, VALUE *argv, VALUE self) | ||
| { | ||
| VALUE e; | ||
| double d = RFLOAT_VALUE(self); | ||
| if (f_negative_p(self)) | ||
| return f_negate(float_rationalize(argc, argv, f_abs(self))); | ||
| if (d < 0.0) | ||
| return nurat_negate(float_rationalize(argc, argv, DBL2NUM(-d))); | ||
| rb_scan_args(argc, argv, "01", &e); | ||
| ... | ... | |
| return 0; | ||
| { | ||
| VALUE l = f_expt10(INT2NUM(count)); | ||
| *num = f_mul(*num, l); | ||
| *num = f_add(*num, fp); | ||
| *num = f_div(*num, l); | ||
| #ifdef CANON | ||
| if (canonicalization) { | ||
| *num = rb_int_mul(*num, l); | ||
| *num = rb_int_plus(*num, fp); | ||
| *num = rb_rational_new2(*num, l); | ||
| } | ||
| else | ||
| #endif | ||
| { | ||
| *num = nurat_mul(*num, l); | ||
| *num = rb_rational_plus(*num, fp); | ||
| *num = nurat_div(*num, l); | ||
| } | ||
| } | ||
| } | ||
| ... | ... | |
| if (!read_digits(s, strict, &exp, NULL)) | ||
| return 0; | ||
| if (expsign == '-') | ||
| exp = f_negate(exp); | ||
| exp = rb_int_uminus(exp); | ||
| } | ||
| if (numsign == '-') | ||
| *num = f_negate(*num); | ||
| *num = nurat_negate(*num); | ||
| if (!NIL_P(exp)) { | ||
| VALUE l = f_expt10(exp); | ||
| *num = f_mul(*num, l); | ||
| *num = nurat_mul(*num, l); | ||
| } | ||
| return 1; | ||
| } | ||
| ... | ... | |
| if (!read_den(s, strict, &den)) | ||
| return 0; | ||
| if (!(FIXNUM_P(den) && FIX2LONG(den) == 1)) | ||
| *num = f_div(*num, den); | ||
| *num = nurat_div(*num, den); | ||
| } | ||
| return 1; | ||
| } | ||
| ... | ... | |
| rb_match_busy(backref); | ||
| if (RB_TYPE_P(a1, T_FLOAT)) { | ||
| a1 = f_to_r(a1); | ||
| a1 = float_to_r(a1); | ||
| } | ||
| else if (RB_TYPE_P(a1, T_STRING)) { | ||
| a1 = string_to_r_strict(a1); | ||
| } | ||
| if (RB_TYPE_P(a2, T_FLOAT)) { | ||
| a2 = f_to_r(a2); | ||
| a2 = float_to_r(a2); | ||
| } | ||
| else if (RB_TYPE_P(a2, T_STRING)) { | ||
| a2 = string_to_r_strict(a2); | ||
| ... | ... | |
| assert(fprintf(stderr, "assert() is now active\n")); | ||
| id_abs = rb_intern("abs"); | ||
| id_cmp = rb_intern("<=>"); | ||
| id_convert = rb_intern("convert"); | ||
| id_eqeq_p = rb_intern("=="); | ||
| id_expt = rb_intern("**"); | ||
| id_fdiv = rb_intern("fdiv"); | ||
| id_idiv = rb_intern("div"); | ||
| id_integer_p = rb_intern("integer?"); | ||
| id_negate = rb_intern("-@"); | ||
| id_to_f = rb_intern("to_f"); | ||
| id_to_i = rb_intern("to_i"); | ||
| id_truncate = rb_intern("truncate"); | ||
| id_i_num = rb_intern("@numerator"); | ||
| id_i_den = rb_intern("@denominator"); | ||
| ... | ... | |
| rb_define_method(rb_cRational, "numerator", nurat_numerator, 0); | ||
| rb_define_method(rb_cRational, "denominator", nurat_denominator, 0); | ||
| rb_define_method(rb_cRational, "-@", nurat_negate, 0); | ||
| rb_define_method(rb_cRational, "+", rb_rational_plus, 1); | ||
| rb_define_method(rb_cRational, "-", nurat_sub, 1); | ||
| rb_define_method(rb_cRational, "*", nurat_mul, 1); | ||
| ... | ... | |
| rb_define_method(rb_cRational, "rational?", nurat_true, 0); | ||
| rb_define_method(rb_cRational, "exact?", nurat_true, 0); | ||
| #endif | ||
| rb_define_method(rb_cRational, "positive?", nurat_positive_p, 0); | ||
| rb_define_method(rb_cRational, "negative?", nurat_negative_p, 0); | ||
| rb_define_method(rb_cRational, "floor", nurat_floor_n, -1); | ||
| rb_define_method(rb_cRational, "ceil", nurat_ceil_n, -1); | ||