In Files

  • rational.c

Rational

Public Instance Methods

%(p1) click to toggle source
 
               static VALUE
nurat_mod(VALUE self, VALUE other)
{
    VALUE val = f_floor(f_div(self, other));
    return f_sub(self, f_mul(other, val));
}
            
*(p1) click to toggle source
 
               static VALUE
nurat_mul(VALUE self, VALUE other)
{
    switch (TYPE(other)) {
      case T_FIXNUM:
      case T_BIGNUM:
        {
            get_dat1(self);

            return f_muldiv(self,
                            dat->num, dat->den,
                            other, ONE, '*');
        }
      case T_FLOAT:
        return f_mul(f_to_f(self), other);
      case T_RATIONAL:
        {
            get_dat2(self, other);

            return f_muldiv(self,
                            adat->num, adat->den,
                            bdat->num, bdat->den, '*');
        }
      default:
        return rb_num_coerce_bin(self, other, '*');
    }
}
            
**(p1) click to toggle source
 
               static VALUE
nurat_expt(VALUE self, VALUE other)
{
    if (k_exact_p(other) && f_zero_p(other))
        return f_rational_new_bang1(CLASS_OF(self), ONE);

    if (k_rational_p(other)) {
        get_dat1(other);

        if (f_one_p(dat->den))
            other = dat->num; /* good? */
    }

    switch (TYPE(other)) {
      case T_FIXNUM:
      case T_BIGNUM:
        {
            VALUE num, den;

            get_dat1(self);

            switch (FIX2INT(f_cmp(other, ZERO))) {
              case 1:
                num = f_expt(dat->num, other);
                den = f_expt(dat->den, other);
                break;
              case -1:
                num = f_expt(dat->den, f_negate(other));
                den = f_expt(dat->num, f_negate(other));
                break;
              default:
                num = ONE;
                den = ONE;
                break;
            }
            return f_rational_new2(CLASS_OF(self), num, den);
        }
      case T_FLOAT:
      case T_RATIONAL:
        return f_expt(f_to_f(self), other);
      default:
        return rb_num_coerce_bin(self, other, id_expt);
    }
}
            
+(p1) click to toggle source
 
               static VALUE
nurat_add(VALUE self, VALUE other)
{
    switch (TYPE(other)) {
      case T_FIXNUM:
      case T_BIGNUM:
        {
            get_dat1(self);

            return f_addsub(self,
                            dat->num, dat->den,
                            other, ONE, '+');
        }
      case T_FLOAT:
        return f_add(f_to_f(self), other);
      case T_RATIONAL:
        {
            get_dat2(self, other);

            return f_addsub(self,
                            adat->num, adat->den,
                            bdat->num, bdat->den, '+');
        }
      default:
        return rb_num_coerce_bin(self, other, '+');
    }
}
            
-(p1) click to toggle source
 
               static VALUE
nurat_sub(VALUE self, VALUE other)
{
    switch (TYPE(other)) {
      case T_FIXNUM:
      case T_BIGNUM:
        {
            get_dat1(self);

            return f_addsub(self,
                            dat->num, dat->den,
                            other, ONE, '-');
        }
      case T_FLOAT:
        return f_sub(f_to_f(self), other);
      case T_RATIONAL:
        {
            get_dat2(self, other);

            return f_addsub(self,
                            adat->num, adat->den,
                            bdat->num, bdat->den, '-');
        }
      default:
        return rb_num_coerce_bin(self, other, '-');
    }
}
            
/(p1) click to toggle source
 
               static VALUE
nurat_div(VALUE self, VALUE other)
{
    switch (TYPE(other)) {
      case T_FIXNUM:
      case T_BIGNUM:
        if (f_zero_p(other))
            rb_raise_zerodiv();
        {
            get_dat1(self);

            return f_muldiv(self,
                            dat->num, dat->den,
                            other, ONE, '/');
        }
      case T_FLOAT:
        return rb_funcall(f_to_f(self), '/', 1, other);
      case T_RATIONAL:
        if (f_zero_p(other))
            rb_raise_zerodiv();
        {
            get_dat2(self, other);

            return f_muldiv(self,
                            adat->num, adat->den,
                            bdat->num, bdat->den, '/');
        }
      default:
        return rb_num_coerce_bin(self, other, '/');
    }
}
            
//(p1) click to toggle source
 
               static VALUE
nurat_idiv(VALUE self, VALUE other)
{
    return f_floor(f_div(self, other));
}
            
<=>(p1) click to toggle source
 
               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);
            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);
    }
}
            
==(p1) click to toggle source
 
               static VALUE
nurat_equal_p(VALUE self, VALUE other)
{
    switch (TYPE(other)) {
      case T_FIXNUM:
      case T_BIGNUM:
        {
            get_dat1(self);

            if (f_zero_p(dat->num) && f_zero_p(other))
                return Qtrue;

            if (!FIXNUM_P(dat->den))
                return Qfalse;
            if (FIX2LONG(dat->den) != 1)
                return Qfalse;
            if (f_equal_p(dat->num, other))
                return Qtrue;
            return Qfalse;
        }
      case T_FLOAT:
        return f_equal_p(f_to_f(self), other);
      case T_RATIONAL:
        {
            get_dat2(self, other);

            if (f_zero_p(adat->num) && f_zero_p(bdat->num))
                return Qtrue;

            return f_boolcast(f_equal_p(adat->num, bdat->num) &&
                              f_equal_p(adat->den, bdat->den));
        }
      default:
        return f_equal_p(other, self);
    }
}
            
abs() click to toggle source
 
               static VALUE
nurat_abs(VALUE self)
{
    if (f_positive_p(self))
        return self;
    return f_negate(self);
}
            
ceil() click to toggle source
 
               static VALUE
nurat_ceil(VALUE self)
{
    get_dat1(self);
    return f_negate(f_idiv(f_negate(dat->num), dat->den));
}
            
coerce(p1) click to toggle source
 
               static VALUE
nurat_coerce(VALUE self, VALUE other)
{
    switch (TYPE(other)) {
      case T_FIXNUM:
      case T_BIGNUM:
        return rb_assoc_new(f_rational_new_bang1(CLASS_OF(self), other), self);
      case T_FLOAT:
        return rb_assoc_new(other, f_to_f(self));
      case T_RATIONAL:
        return rb_assoc_new(other, self);
      case T_COMPLEX:
        if (k_exact_p(RCOMPLEX(other)->imag) && f_zero_p(RCOMPLEX(other)->imag))
            return rb_assoc_new(f_rational_new_bang1
                                (CLASS_OF(self), RCOMPLEX(other)->real), self);
    }

    rb_raise(rb_eTypeError, "%s can't be coerced into %s",
             rb_obj_classname(other), rb_obj_classname(self));
    return Qnil;
}
            
denominator() click to toggle source
 
               static VALUE
nurat_denominator(VALUE self)
{
    get_dat1(self);
    return dat->den;
}
            
div(p1) click to toggle source
 
               static VALUE
nurat_idiv(VALUE self, VALUE other)
{
    return f_floor(f_div(self, other));
}
            
divmod(p1) click to toggle source
 
               static VALUE
nurat_divmod(VALUE self, VALUE other)
{
    VALUE val = f_floor(f_div(self, other));
    return rb_assoc_new(val, f_sub(self, f_mul(other, val)));
}
            
exact?() click to toggle source
 
               static VALUE
nurat_true(VALUE self)
{
    return Qtrue;
}
            
fdiv(p1) click to toggle source
 
               static VALUE
nurat_fdiv(VALUE self, VALUE other)
{
    return f_div(f_to_f(self), other);
}
            
floor() click to toggle source
 
               static VALUE
nurat_floor(VALUE self)
{
    get_dat1(self);
    return f_idiv(dat->num, dat->den);
}
            
hash() click to toggle source
 
               static VALUE
nurat_hash(VALUE self)
{
    get_dat1(self);
    return f_xor(f_hash(dat->num), f_hash(dat->den));
}
            
inspect() click to toggle source
 
               static VALUE
nurat_inspect(VALUE self)
{
    VALUE s;

    s = rb_usascii_str_new2("(");
    rb_str_concat(s, nurat_format(self, f_inspect));
    rb_str_cat2(s, ")");

    return s;
}
            
marshal_dump() click to toggle source
 
               static VALUE
nurat_marshal_dump(VALUE self)
{
    VALUE a;
    get_dat1(self);

    a = rb_assoc_new(dat->num, dat->den);
    rb_copy_generic_ivar(a, self);
    return a;
}
            
marshal_load(p1) click to toggle source
 
               static VALUE
nurat_marshal_load(VALUE self, VALUE a)
{
    get_dat1(self);
    dat->num = RARRAY_PTR(a)[0];
    dat->den = RARRAY_PTR(a)[1];
    rb_copy_generic_ivar(self, a);

    if (f_zero_p(dat->den))
        rb_raise_zerodiv();

    return self;
}
            
modulo(p1) click to toggle source
 
               static VALUE
nurat_mod(VALUE self, VALUE other)
{
    VALUE val = f_floor(f_div(self, other));
    return f_sub(self, f_mul(other, val));
}
            
numerator() click to toggle source
 
               static VALUE
nurat_numerator(VALUE self)
{
    get_dat1(self);
    return dat->num;
}
            
quo(p1) click to toggle source
 
               static VALUE
nurat_div(VALUE self, VALUE other)
{
    switch (TYPE(other)) {
      case T_FIXNUM:
      case T_BIGNUM:
        if (f_zero_p(other))
            rb_raise_zerodiv();
        {
            get_dat1(self);

            return f_muldiv(self,
                            dat->num, dat->den,
                            other, ONE, '/');
        }
      case T_FLOAT:
        return rb_funcall(f_to_f(self), '/', 1, other);
      case T_RATIONAL:
        if (f_zero_p(other))
            rb_raise_zerodiv();
        {
            get_dat2(self, other);

            return f_muldiv(self,
                            adat->num, adat->den,
                            bdat->num, bdat->den, '/');
        }
      default:
        return rb_num_coerce_bin(self, other, '/');
    }
}
            
quot(p1) click to toggle source
 
               static VALUE
nurat_quot(VALUE self, VALUE other)
{
    return f_truncate(f_div(self, other));
}
            
quotrem(p1) click to toggle source
 
               static VALUE
nurat_quotrem(VALUE self, VALUE other)
{
    VALUE val = f_truncate(f_div(self, other));
    return rb_assoc_new(val, f_sub(self, f_mul(other, val)));
}
            
rational?() click to toggle source
 
               static VALUE
nurat_true(VALUE self)
{
    return Qtrue;
}
            
remainder(p1) click to toggle source
 
               static VALUE
nurat_rem(VALUE self, VALUE other)
{
    VALUE val = f_truncate(f_div(self, other));
    return f_sub(self, f_mul(other, val));
}
            
round() click to toggle source
 
               static VALUE
nurat_round(VALUE self)
{
    get_dat1(self);

    if (f_negative_p(dat->num)) {
        VALUE num, den;

        num = f_negate(dat->num);
        num = f_add(f_mul(num, TWO), dat->den);
        den = f_mul(dat->den, TWO);
        return f_negate(f_idiv(num, den));
    }
    else {
        VALUE num = f_add(f_mul(dat->num, TWO), dat->den);
        VALUE den = f_mul(dat->den, TWO);
        return f_idiv(num, den);
    }
}
            
to_f() click to toggle source
 
               static VALUE
nurat_to_f(VALUE self)
{
    VALUE num, den;
    int minus = 0;
    long nl, dl, ne, de;
    int e;
    double f;

    {
        get_dat1(self);

        if (f_zero_p(dat->num))
            return rb_float_new(0.0);

        num = dat->num;
        den = dat->den;
    }

    if (f_negative_p(num)) {
        num = f_negate(num);
        minus = 1;
    }

    nl = i_ilog2(num);
    dl = i_ilog2(den);

    ne = 0;
    if (nl > ml) {
        ne = nl - ml;
        num = f_rshift(num, LONG2NUM(ne));
    }

    de = 0;
    if (dl > ml) {
        de = dl - ml;
        den = f_rshift(den, LONG2NUM(de));
    }

    e = (int)(ne - de);

    if ((e > DBL_MAX_EXP) || (e < DBL_MIN_EXP)) {
        rb_warning("%s out of Float range", rb_obj_classname(self));
        return rb_float_new(e > 0 ? HUGE_VAL : 0.0);
    }

    f = NUM2DBL(num) / NUM2DBL(den);
    if (minus)
        f = -f;
    f = ldexp(f, e);

    if (isinf(f) || isnan(f))
        rb_warning("%s out of Float range", rb_obj_classname(self));

    return rb_float_new(f);
}
            
to_i() click to toggle source
 
               static VALUE
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);
}
            
to_r() click to toggle source
 
               static VALUE
nurat_to_r(VALUE self)
{
    return self;
}
            
to_s() click to toggle source
 
               static VALUE
nurat_to_s(VALUE self)
{
    return nurat_format(self, f_to_s);
}
            
truncate() click to toggle source
 
               static VALUE
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);
}