Class: Rational (Ruby 2.3.4)

    In Files

    • rational.c

    Class/Module Index [+]

    Quicksearch

    Rational

    A rational number can be represented as a paired integer number; a/b (b>0). Where a is numerator and b is denominator. Integer a equals rational a/1 mathematically.

    In ruby, you can create rational object with Rational, #to_r, rationalize method or suffixing r to a literal. The return values will be irreducible.

    Rational(1)      #=> (1/1)
    Rational(2, 3)   #=> (2/3)
    Rational(4, -6)  #=> (-2/3)
    3.to_r           #=> (3/1)
    2/3r             #=> (2/3)

    You can also create rational object from floating-point numbers or strings.

    Rational(0.3)    #=> (5404319552844595/18014398509481984)
    Rational('0.3')  #=> (3/10)
    Rational('2/3')  #=> (2/3)
    
    0.3.to_r         #=> (5404319552844595/18014398509481984)
    '0.3'.to_r       #=> (3/10)
    '2/3'.to_r       #=> (2/3)
    0.3.rationalize  #=> (3/10)
    

    A rational object is an exact number, which helps you to write program without any rounding errors.

    10.times.inject(0){|t,| t + 0.1}              #=> 0.9999999999999999
    10.times.inject(0){|t,| t + Rational('0.1')}  #=> (1/1)
    

    However, when an expression has inexact factor (numerical value or operation), will produce an inexact result.

    Rational(10) / 3   #=> (10/3)
    Rational(10) / 3.0 #=> 3.3333333333333335
    
    Rational(-8) ** Rational(1, 3)
                       #=> (1.0000000000000002+1.7320508075688772i)
    

    Public Instance Methods

    rat * numeric → numeric click to toggle source

    Performs multiplication.

    Rational(2, 3)  * Rational(2, 3)   #=> (4/9)
    Rational(900)   * Rational(1)      #=> (900/1)
    Rational(-2, 9) * Rational(-9, 2)  #=> (1/1)
    Rational(9, 8)  * 4                #=> (9/2)
    Rational(20, 9) * 9.8              #=> 21.77777777777778
    
     
                   static VALUE
    nurat_mul(VALUE self, VALUE other)
    {
        if (RB_TYPE_P(other, T_FIXNUM) || RB_TYPE_P(other, T_BIGNUM)) {
            {
                get_dat1(self);
    
                return f_muldiv(self,
                                dat->num, dat->den,
                                other, ONE, '*');
            }
        }
        else if (RB_TYPE_P(other, T_FLOAT)) {
            return f_mul(f_to_f(self), other);
        }
        else if (RB_TYPE_P(other, T_RATIONAL)) {
            {
                get_dat2(self, other);
    
                return f_muldiv(self,
                                adat->num, adat->den,
                                bdat->num, bdat->den, '*');
            }
        }
        else {
            return rb_num_coerce_bin(self, other, '*');
        }
    }
                
    rat ** numeric → numeric click to toggle source

    Performs exponentiation.

    Rational(2)    ** Rational(3)    #=> (8/1)
    Rational(10)   ** -2             #=> (1/100)
    Rational(10)   ** -2.0           #=> 0.01
    Rational(-4)   ** Rational(1,2)  #=> (1.2246063538223773e-16+2.0i)
    Rational(1, 2) ** 0              #=> (1/1)
    Rational(1, 2) ** 0.0            #=> 1.0
    
     
                   static VALUE
    nurat_expt(VALUE self, VALUE other)
    {
        if (k_numeric_p(other) && k_exact_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; /* c14n */
        }
    
        /* Deal with special cases of 0**n and 1**n */
        if (k_numeric_p(other) && k_exact_p(other)) {
            get_dat1(self);
            if (f_one_p(dat->den)) {
                if (f_one_p(dat->num)) {
                    return f_rational_new_bang1(CLASS_OF(self), ONE);
                }
                else if (f_minus_one_p(dat->num) && k_integer_p(other)) {
                    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();
                    }
                    else {
                        return f_rational_new_bang1(CLASS_OF(self), ZERO);
                    }
                }
            }
        }
    
        /* General case */
        if (RB_TYPE_P(other, T_FIXNUM)) {
            {
                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;
                }
                if (RB_FLOAT_TYPE_P(num)) { /* infinity due to overflow */
                    if (RB_FLOAT_TYPE_P(den)) return DBL2NUM(NAN);
                    return num;
                }
                if (RB_FLOAT_TYPE_P(den)) { /* infinity due to overflow */
                    num = ZERO;
                    den = ONE;
                }
                return f_rational_new2(CLASS_OF(self), num, den);
            }
        }
        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);
        }
        else if (RB_TYPE_P(other, T_FLOAT) || RB_TYPE_P(other, T_RATIONAL)) {
            return f_expt(f_to_f(self), other);
        }
        else {
            return rb_num_coerce_bin(self, other, id_expt);
        }
    }
                
    rat + numeric → numeric click to toggle source

    Performs addition.

    Rational(2, 3)  + Rational(2, 3)   #=> (4/3)
    Rational(900)   + Rational(1)      #=> (901/1)
    Rational(-2, 9) + Rational(-9, 2)  #=> (-85/18)
    Rational(9, 8)  + 4                #=> (41/8)
    Rational(20, 9) + 9.8              #=> 12.022222222222222
    
     
                   static VALUE
    nurat_add(VALUE self, VALUE other)
    {
        if (RB_TYPE_P(other, T_FIXNUM) || RB_TYPE_P(other, T_BIGNUM)) {
            {
                get_dat1(self);
    
                return f_addsub(self,
                                dat->num, dat->den,
                                other, ONE, '+');
            }
        }
        else if (RB_TYPE_P(other, T_FLOAT)) {
            return f_add(f_to_f(self), other);
        }
        else if (RB_TYPE_P(other, T_RATIONAL)) {
            {
                get_dat2(self, other);
    
                return f_addsub(self,
                                adat->num, adat->den,
                                bdat->num, bdat->den, '+');
            }
        }
        else {
            return rb_num_coerce_bin(self, other, '+');
        }
    }
                
    rat - numeric → numeric click to toggle source

    Performs subtraction.

    Rational(2, 3)  - Rational(2, 3)   #=> (0/1)
    Rational(900)   - Rational(1)      #=> (899/1)
    Rational(-2, 9) - Rational(-9, 2)  #=> (77/18)
    Rational(9, 8)  - 4                #=> (23/8)
    Rational(20, 9) - 9.8              #=> -7.577777777777778
    
     
                   static VALUE
    nurat_sub(VALUE self, VALUE other)
    {
        if (RB_TYPE_P(other, T_FIXNUM) || RB_TYPE_P(other, T_BIGNUM)) {
            {
                get_dat1(self);
    
                return f_addsub(self,
                                dat->num, dat->den,
                                other, ONE, '-');
            }
        }
        else if (RB_TYPE_P(other, T_FLOAT)) {
            return f_sub(f_to_f(self), other);
        }
        else if (RB_TYPE_P(other, T_RATIONAL)) {
            {
                get_dat2(self, other);
    
                return f_addsub(self,
                                adat->num, adat->den,
                                bdat->num, bdat->den, '-');
            }
        }
        else {
            return rb_num_coerce_bin(self, other, '-');
        }
    }
                
    rat / numeric → numeric click to toggle source

    Performs division.

    Rational(2, 3)  / Rational(2, 3)   #=> (1/1)
    Rational(900)   / Rational(1)      #=> (900/1)
    Rational(-2, 9) / Rational(-9, 2)  #=> (4/81)
    Rational(9, 8)  / 4                #=> (9/32)
    Rational(20, 9) / 9.8              #=> 0.22675736961451246
    
     
                   static VALUE
    nurat_div(VALUE self, VALUE other)
    {
        if (RB_TYPE_P(other, T_FIXNUM) || RB_TYPE_P(other, T_BIGNUM)) {
            if (f_zero_p(other))
                rb_raise_zerodiv();
            {
                get_dat1(self);
    
                return f_muldiv(self,
                                dat->num, dat->den,
                                other, ONE, '/');
            }
        }
        else if (RB_TYPE_P(other, T_FLOAT))
            return rb_funcall(f_to_f(self), '/', 1, other);
        else if (RB_TYPE_P(other, T_RATIONAL)) {
            if (f_zero_p(other))
                rb_raise_zerodiv();
            {
                get_dat2(self, other);
    
                if (f_one_p(self))
                    return f_rational_new_no_reduce2(CLASS_OF(self),
                                                     bdat->den, bdat->num);
    
                return f_muldiv(self,
                                adat->num, adat->den,
                                bdat->num, bdat->den, '/');
            }
        }
        else {
            return rb_num_coerce_bin(self, other, '/');
        }
    }
                
    rational <=> numeric → -1, 0, +1 or nil click to toggle source

    Performs comparison and returns -1, 0, or +1.

    nil is returned if the two values are incomparable.

    Rational(2, 3)  <=> Rational(2, 3)  #=> 0
    Rational(5)     <=> 5               #=> 0
    Rational(2,3)   <=> Rational(1,3)   #=> 1
    Rational(1,3)   <=> 1               #=> -1
    Rational(1,3)   <=> 0.3             #=> 1
    
     
                   static VALUE
    nurat_cmp(VALUE self, VALUE other)
    {
        if (RB_TYPE_P(other, T_FIXNUM) || RB_TYPE_P(other, T_BIGNUM)) {
            {
                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));
            }
        }
        else if (RB_TYPE_P(other, T_FLOAT)) {
            return f_cmp(f_to_f(self), other);
        }
        else if (RB_TYPE_P(other, 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);
            }
        }
        else {
            return rb_num_coerce_cmp(self, other, id_cmp);
        }
    }
                
    rat == object → true or false click to toggle source

    Returns true if rat equals object numerically.

    Rational(2, 3)  == Rational(2, 3)   #=> true
    Rational(5)     == 5                #=> true
    Rational(0)     == 0.0              #=> true
    Rational('1/3') == 0.33             #=> false
    Rational('1/2') == '1/2'            #=> false
    
     
                   static VALUE
    nurat_eqeq_p(VALUE self, VALUE other)
    {
        if (RB_TYPE_P(other, T_FIXNUM) || RB_TYPE_P(other, 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_eqeq_p(dat->num, other))
                    return Qtrue;
                return Qfalse;
            }
        }
        else if (RB_TYPE_P(other, T_FLOAT)) {
            return f_eqeq_p(f_to_f(self), other);
        }
        else if (RB_TYPE_P(other, T_RATIONAL)) {
            {
                get_dat2(self, other);
    
                if (f_zero_p(adat->num) && f_zero_p(bdat->num))
                    return Qtrue;
    
                return f_boolcast(f_eqeq_p(adat->num, bdat->num) &&
                                  f_eqeq_p(adat->den, bdat->den));
            }
        }
        else {
            return f_eqeq_p(other, self);
        }
    }
                
    ceil → integer click to toggle source
    ceil(precision=0) → rational

    Returns the truncated value (toward positive infinity).

    Rational(3).ceil      #=> 3
    Rational(2, 3).ceil   #=> 1
    Rational(-3, 2).ceil  #=> -1
    
           decimal      -  1  2  3 . 4  5  6
                          ^  ^  ^  ^   ^  ^
          precision      -3 -2 -1  0  +1 +2
    
    '%f' % Rational('-123.456').ceil(+1)  #=> "-123.400000"
    '%f' % Rational('-123.456').ceil(-1)  #=> "-120.000000"
     
                   static VALUE
    nurat_ceil_n(int argc, VALUE *argv, VALUE self)
    {
        return f_round_common(argc, argv, self, nurat_ceil);
    }
                
    denominator → integer click to toggle source

    Returns the denominator (always positive).

    Rational(7).denominator             #=> 1
    Rational(7, 1).denominator          #=> 1
    Rational(9, -4).denominator         #=> 4
    Rational(-2, -10).denominator       #=> 5
    rat.numerator.gcd(rat.denominator)  #=> 1
    
     
                   static VALUE
    nurat_denominator(VALUE self)
    {
        get_dat1(self);
        return dat->den;
    }
                
    fdiv(numeric) → float click to toggle source

    Performs division and returns the value as a float.

    Rational(2, 3).fdiv(1)       #=> 0.6666666666666666
    Rational(2, 3).fdiv(0.5)     #=> 1.3333333333333333
    Rational(2).fdiv(3)          #=> 0.6666666666666666
    
     
                   static VALUE
    nurat_fdiv(VALUE self, VALUE other)
    {
        if (f_zero_p(other))
            return f_div(self, f_to_f(other));
        return f_to_f(f_div(self, other));
    }
                
    floor → integer click to toggle source
    floor(precision=0) → rational

    Returns the truncated value (toward negative infinity).

    Rational(3).floor      #=> 3
    Rational(2, 3).floor   #=> 0
    Rational(-3, 2).floor  #=> -1
    
           decimal      -  1  2  3 . 4  5  6
                          ^  ^  ^  ^   ^  ^
          precision      -3 -2 -1  0  +1 +2
    
    '%f' % Rational('-123.456').floor(+1)  #=> "-123.500000"
    '%f' % Rational('-123.456').floor(-1)  #=> "-130.000000"
     
                   static VALUE
    nurat_floor_n(int argc, VALUE *argv, VALUE self)
    {
        return f_round_common(argc, argv, self, nurat_floor);
    }
                
    inspect → string click to toggle source

    Returns the value as a string for inspection.

    Rational(2).inspect      #=> "(2/1)"
    Rational(-8, 6).inspect  #=> "(-4/3)"
    Rational('1/2').inspect  #=> "(1/2)"
    
     
                   static VALUE
    nurat_inspect(VALUE self)
    {
        VALUE s;
    
        s = rb_usascii_str_new2("(");
        rb_str_concat(s, f_format(self, f_inspect));
        rb_str_cat2(s, ")");
    
        return s;
    }
                
    numerator → integer click to toggle source

    Returns the numerator.

    Rational(7).numerator        #=> 7
    Rational(7, 1).numerator     #=> 7
    Rational(9, -4).numerator    #=> -9
    Rational(-2, -10).numerator  #=> 1
    
     
                   static VALUE
    nurat_numerator(VALUE self)
    {
        get_dat1(self);
        return dat->num;
    }
                
    quo(numeric) → numeric click to toggle source

    Performs division.

    Rational(2, 3)  / Rational(2, 3)   #=> (1/1)
    Rational(900)   / Rational(1)      #=> (900/1)
    Rational(-2, 9) / Rational(-9, 2)  #=> (4/81)
    Rational(9, 8)  / 4                #=> (9/32)
    Rational(20, 9) / 9.8              #=> 0.22675736961451246
    
     
                   static VALUE
    nurat_div(VALUE self, VALUE other)
    {
        if (RB_TYPE_P(other, T_FIXNUM) || RB_TYPE_P(other, T_BIGNUM)) {
            if (f_zero_p(other))
                rb_raise_zerodiv();
            {
                get_dat1(self);
    
                return f_muldiv(self,
                                dat->num, dat->den,
                                other, ONE, '/');
            }
        }
        else if (RB_TYPE_P(other, T_FLOAT))
            return rb_funcall(f_to_f(self), '/', 1, other);
        else if (RB_TYPE_P(other, T_RATIONAL)) {
            if (f_zero_p(other))
                rb_raise_zerodiv();
            {
                get_dat2(self, other);
    
                if (f_one_p(self))
                    return f_rational_new_no_reduce2(CLASS_OF(self),
                                                     bdat->den, bdat->num);
    
                return f_muldiv(self,
                                adat->num, adat->den,
                                bdat->num, bdat->den, '/');
            }
        }
        else {
            return rb_num_coerce_bin(self, other, '/');
        }
    }
                
    rationalize → self click to toggle source
    rationalize(eps) → rational

    Returns a simpler approximation of the value if the optional argument eps is given (rat-|eps| <= result <= rat+|eps|), self otherwise.

    r = Rational(5033165, 16777216)
    r.rationalize                    #=> (5033165/16777216)
    r.rationalize(Rational('0.01'))  #=> (3/10)
    r.rationalize(Rational('0.1'))   #=> (1/3)
    
     
                   static VALUE
    nurat_rationalize(int argc, VALUE *argv, VALUE self)
    {
        VALUE e, a, b, p, q;
    
        if (argc == 0)
            return self;
    
        if (f_negative_p(self))
            return f_negate(nurat_rationalize(argc, argv, f_abs(self)));
    
        rb_scan_args(argc, argv, "01", &e);
        e = f_abs(e);
        a = f_sub(self, e);
        b = f_add(self, e);
    
        if (f_eqeq_p(a, b))
            return self;
    
        nurat_rationalize_internal(a, b, &p, &q);
        return f_rational_new2(CLASS_OF(self), p, q);
    }
                
    round → integer click to toggle source
    round(precision=0) → rational

    Returns the truncated value (toward the nearest integer; 0.5 => 1; -0.5 => -1).

    Rational(3).round      #=> 3
    Rational(2, 3).round   #=> 1
    Rational(-3, 2).round  #=> -2
    
           decimal      -  1  2  3 . 4  5  6
                          ^  ^  ^  ^   ^  ^
          precision      -3 -2 -1  0  +1 +2
    
    '%f' % Rational('-123.456').round(+1)  #=> "-123.500000"
    '%f' % Rational('-123.456').round(-1)  #=> "-120.000000"
     
                   static VALUE
    nurat_round_n(int argc, VALUE *argv, VALUE self)
    {
        return f_round_common(argc, argv, self, nurat_round);
    }
                
    to_f → float click to toggle source

    Return the value as a float.

    Rational(2).to_f      #=> 2.0
    Rational(9, 4).to_f   #=> 2.25
    Rational(-3, 4).to_f  #=> -0.75
    Rational(20, 3).to_f  #=> 6.666666666666667
    
     
                   static VALUE
    nurat_to_f(VALUE self)
    {
        get_dat1(self);
        return f_fdiv(dat->num, dat->den);
    }
                
    to_i → integer click to toggle source

    Returns the truncated value as an integer.

    Equivalent to

    rat.truncate.
    
    Rational(2, 3).to_i   #=> 0
    Rational(3).to_i      #=> 3
    Rational(300.6).to_i  #=> 300
    Rational(98,71).to_i  #=> 1
    Rational(-30,2).to_i  #=> -15
    
     
                   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 → self click to toggle source

    Returns self.

    Rational(2).to_r      #=> (2/1)
    Rational(-8, 6).to_r  #=> (-4/3)
    
     
                   static VALUE
    nurat_to_r(VALUE self)
    {
        return self;
    }
                
    to_s → string click to toggle source

    Returns the value as a string.

    Rational(2).to_s      #=> "2/1"
    Rational(-8, 6).to_s  #=> "-4/3"
    Rational('1/2').to_s  #=> "1/2"
    
     
                   static VALUE
    nurat_to_s(VALUE self)
    {
        return f_format(self, f_to_s);
    }
                
    truncate → integer click to toggle source
    truncate(precision=0) → rational

    Returns the truncated value (toward zero).

    Rational(3).truncate      #=> 3
    Rational(2, 3).truncate   #=> 0
    Rational(-3, 2).truncate  #=> -1
    
           decimal      -  1  2  3 . 4  5  6
                          ^  ^  ^  ^   ^  ^
          precision      -3 -2 -1  0  +1 +2
    
    '%f' % Rational('-123.456').truncate(+1)  #=>  "-123.400000"
    '%f' % Rational('-123.456').truncate(-1)  #=>  "-120.000000"
     
                   static VALUE
    nurat_truncate_n(int argc, VALUE *argv, VALUE self)
    {
        return f_round_common(argc, argv, self, nurat_truncate);
    }