inline static VALUE f_addsub(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k) { VALUE num, den; if (FIXNUM_P(anum) && FIXNUM_P(aden) && FIXNUM_P(bnum) && FIXNUM_P(bden)) { long an = FIX2LONG(anum); long ad = FIX2LONG(aden); long bn = FIX2LONG(bnum); long bd = FIX2LONG(bden); long ig = i_gcd(ad, bd); VALUE g = LONG2NUM(ig); VALUE a = f_imul(an, bd / ig); VALUE b = f_imul(bn, ad / ig); VALUE c; if (k == '+') c = f_add(a, b); else c = f_sub(a, b); b = f_idiv(aden, g); g = f_gcd(c, g); num = f_idiv(c, g); a = f_idiv(bden, g); den = f_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 c; if (k == '+') c = f_add(a, b); else c = f_sub(a, b); b = f_idiv(aden, g); g = f_gcd(c, g); num = f_idiv(c, g); a = f_idiv(bden, g); den = f_mul(a, b); } return f_rational_new_no_reduce2(CLASS_OF(self), num, den); }
inline static VALUE f_muldiv(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k) { VALUE num, den; if (k == '/') { VALUE t; if (f_negative_p(bnum)) { anum = f_negate(anum); bnum = f_negate(bnum); } t = bnum; bnum = bden; bden = t; } if (FIXNUM_P(anum) && FIXNUM_P(aden) && FIXNUM_P(bnum) && FIXNUM_P(bden)) { long an = FIX2LONG(anum); long ad = FIX2LONG(aden); long bn = FIX2LONG(bnum); long bd = FIX2LONG(bden); long g1 = i_gcd(an, bd); long g2 = i_gcd(ad, bn); num = f_imul(an / g1, bn / g2); den = f_imul(ad / g2, bd / g1); } else { 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)); } return f_rational_new_no_reduce2(CLASS_OF(self), num, den); }
static VALUE nurat_cmp(VALUE self, VALUE other) { switch (TYPE(other)) { case T_FIXNUM: case T_BIGNUM: { get_dat1(self); if (FIXNUM_P(dat->den) && FIX2LONG(dat->den) == 1) return f_cmp(dat->num, other); else return f_cmp(self, f_rational_new_bang1(CLASS_OF(self), other)); } case T_FLOAT: return f_cmp(f_to_f(self), other); case T_RATIONAL: { VALUE num1, num2; get_dat2(self, other); if (FIXNUM_P(adat->num) && FIXNUM_P(adat->den) && FIXNUM_P(bdat->num) && FIXNUM_P(bdat->den)) { num1 = f_imul(FIX2LONG(adat->num), FIX2LONG(bdat->den)); num2 = f_imul(FIX2LONG(bdat->num), FIX2LONG(adat->den)); } else { num1 = f_mul(adat->num, bdat->den); num2 = f_mul(bdat->num, adat->den); } return f_cmp(f_sub(num1, num2), ZERO); } default: return rb_num_coerce_bin(self, other, id_cmp); } }