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);
}
            

Commenting is here to help enhance the documentation. For example, code samples, or clarification of the documentation.

If you have questions about Ruby or the documentation, please post to one of the Ruby mailing lists. You will get better, faster, help that way.

If you wish to post a correction of the docs, please do so, but also file bug report so that it can be corrected for the next release. Thank you.

If you want to help improve the Ruby documentation, please visit Documenting-ruby.org.

blog comments powered by Disqus