When mathn is required Rational is changed to simplify the use of Rational operations.
Normal behaviour:
Rational.new!(1,3) ** 2 # => Rational(1, 9)
(1 / 3) ** 2            # => 0
require 'mathn' behaviour:
(1 / 3) ** 2            # => 1/9
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 or rationalize method. 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)
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)
- #
- A
- C
- D
- F
- I
- J
- N
- Q
- R
- T
Performs multiplication.
For example:
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
Source: show
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, '*');
    }
}
              Exponentiate by other
(1/3) ** 2 # => 1/9
# File ../ruby/lib/mathn.rb, line 138 def ** (other) if other.kind_of?(Rational) other2 = other if self < 0 return Complex(self, 0.0) ** other elsif other == 0 return Rational(1,1) elsif self == 0 return Rational(0,1) elsif self == 1 return Rational(1,1) end npd = numerator.prime_division dpd = denominator.prime_division if other < 0 other = -other npd, dpd = dpd, npd end for elm in npd elm[1] = elm[1] * other if !elm[1].kind_of?(Integer) and elm[1].denominator != 1 return Float(self) ** other2 end elm[1] = elm[1].to_i end for elm in dpd elm[1] = elm[1] * other if !elm[1].kind_of?(Integer) and elm[1].denominator != 1 return Float(self) ** other2 end elm[1] = elm[1].to_i end num = Integer.from_prime_division(npd) den = Integer.from_prime_division(dpd) Rational(num,den) elsif other.kind_of?(Integer) if other > 0 num = numerator ** other den = denominator ** other elsif other < 0 num = denominator ** -other den = numerator ** -other elsif other == 0 num = 1 den = 1 end Rational(num, den) elsif other.kind_of?(Float) Float(self) ** other else x , y = other.coerce(self) x ** y end end
Performs addition.
For example:
Rational(2, 3)  + Rational(2, 3)   #=> (4/3)
Rational(900)   + Rational(1)      #=> (900/1)
Rational(-2, 9) + Rational(-9, 2)  #=> (-85/18)
Rational(9, 8)  + 4                #=> (41/8)
Rational(20, 9) + 9.8              #=> 12.022222222222222
Source: show
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, '+');
    }
}
              Performs subtraction.
For example:
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
Source: show
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, '-');
    }
}
              Performs division.
For example:
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
Source: show
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:
        {
            double x = RFLOAT_VALUE(other), den;
            get_dat1(self);
            if (isnan(x)) return DBL2NUM(NAN);
            if (isinf(x)) return INT2FIX(0);
            if (x != 0.0 && modf(x, &den) == 0.0) {
                return rb_rational_raw2(dat->num, f_mul(rb_dbl2big(den), dat->den));
            }
        }
        return rb_funcall(f_to_f(self), '/', 1, other);
      case 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, '/');
        }
      default:
        return rb_num_coerce_bin(self, other, '/');
    }
}
              Performs comparison and returns -1, 0, or +1.
For example:
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
Source: show
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); /* c14n */
            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_cmp(self, other, id_cmp);
    }
}
              Returns true if rat equals object numerically.
For example:
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
Source: show
static VALUE
nurat_eqeq_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_eqeq_p(dat->num, other))
                return Qtrue;
            return Qfalse;
        }
      case T_FLOAT:
        return f_eqeq_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_eqeq_p(adat->num, bdat->num) &&
                              f_eqeq_p(adat->den, bdat->den));
        }
      default:
        return f_eqeq_p(other, self);
    }
}
              Returns the truncated value (toward positive infinity).
For example:
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"
Source: show
static VALUE
nurat_ceil_n(int argc, VALUE *argv, VALUE self)
{
    return f_round_common(argc, argv, self, nurat_ceil);
}
              Returns the denominator (always positive).
For example:
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
Source: show
static VALUE
nurat_denominator(VALUE self)
{
    get_dat1(self);
    return dat->den;
}
              Performs division and returns the value as a float.
For example:
Rational(2, 3).fdiv(1)       #=> 0.6666666666666666
Rational(2, 3).fdiv(0.5)     #=> 1.3333333333333333
Rational(2).fdiv(3)          #=> 0.6666666666666666
Source: show
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));
}
              Returns the truncated value (toward negative infinity).
For example:
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"
Source: show
static VALUE
nurat_floor_n(int argc, VALUE *argv, VALUE self)
{
    return f_round_common(argc, argv, self, nurat_floor);
}
              Returns the value as a string for inspection.
For example:
Rational(2).inspect      #=> "(2/1)"
Rational(-8, 6).inspect  #=> "(-4/3)"
Rational('0.5').inspect  #=> "(1/2)"
Source: show
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;
}
              Returns the numerator.
For example:
Rational(7).numerator        #=> 7
Rational(7, 1).numerator     #=> 7
Rational(9, -4).numerator    #=> -9
Rational(-2, -10).numerator  #=> 1
Source: show
static VALUE
nurat_numerator(VALUE self)
{
    get_dat1(self);
    return dat->num;
}
              Performs division.
For example:
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
Source: show
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:
        {
            double x = RFLOAT_VALUE(other), den;
            get_dat1(self);
            if (isnan(x)) return DBL2NUM(NAN);
            if (isinf(x)) return INT2FIX(0);
            if (x != 0.0 && modf(x, &den) == 0.0) {
                return rb_rational_raw2(dat->num, f_mul(rb_dbl2big(den), dat->den));
            }
        }
        return rb_funcall(f_to_f(self), '/', 1, other);
      case 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, '/');
        }
      default:
        return rb_num_coerce_bin(self, other, '/');
    }
}
              Returns a simpler approximation of the value if an optional argument eps is given (rat-|eps| <= result <= rat+|eps|), self otherwise.
For example:
r = Rational(5033165, 16777216)
r.rationalize                    #=> (5033165/16777216)
r.rationalize(Rational('0.01'))  #=> (3/10)
r.rationalize(Rational('0.1'))   #=> (1/3)
Source: show
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);
}
              Returns the truncated value (toward the nearest integer; 0.5 => 1; -0.5 => -1).
For example:
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"
Source: show
static VALUE
nurat_round_n(int argc, VALUE *argv, VALUE self)
{
    return f_round_common(argc, argv, self, nurat_round);
}
              Converts a Rational to a BigDecimal. Takes an optional parameter
sig to limit the amount of significant digits. If a negative
precision is given, raise ArgumentError.
The zero precision and implicit precision is deprecated.
r = (22/7.0).to_r
# => (7077085128725065/2251799813685248)
r.to_d
# => #<BigDecimal:1a52bd8,'0.3142857142 8571427937 0154144999 105E1',45(63)>
r.to_d(3)
# => #<BigDecimal:1a44d08,'0.314E1',18(36)>
# File ../ruby/ext/bigdecimal/lib/bigdecimal/util.rb, line 99 def to_d(precision=0) if precision < 0 raise ArgumentError, "negative precision" elsif precision == 0 warn "zero and implicit precision is deprecated." precision = BigDecimal.double_fig*2+1 end num = self.numerator BigDecimal(num).div(self.denominator, precision) end
Return the value as a float.
For example:
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
Source: show
static VALUE
nurat_to_f(VALUE self)
{
    get_dat1(self);
    return f_fdiv(dat->num, dat->den);
}
              Returns the truncated value as an integer.
Equivalent to
rat.truncate.For example:
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
Source: show
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);
}
              Returns self.
For example:
Rational(2).to_r      #=> (2/1)
Rational(-8, 6).to_r  #=> (-4/3)
Source: show
static VALUE
nurat_to_r(VALUE self)
{
    return self;
}
              Returns the value as a string.
For example:
Rational(2).to_s      #=> "2/1"
Rational(-8, 6).to_s  #=> "-4/3"
Rational('0.5').to_s  #=> "1/2"
Source: show
static VALUE
nurat_to_s(VALUE self)
{
    return f_format(self, f_to_s);
}
              Returns the truncated value (toward zero).
For example:
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"
Source: show
static VALUE
nurat_truncate_n(int argc, VALUE *argv, VALUE self)
{
    return f_round_common(argc, argv, self, nurat_truncate);
}