# class 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 Class Methods

json_create(object) click to toggle source

Deserializes `JSON` string by converting numerator value `n`, denominator value `d`, to a `Rational` object.

```# File ext/json/lib/json/add/rational.rb, line 10
def self.json_create(object)
Rational(object['n'], object['d'])
end```

### 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_INTEGER_TYPE_P(other)) {
{
get_dat1(self);

return f_muldiv(self,
dat->num, dat->den,
other, ONE, '*');
}
}
else if (RB_FLOAT_TYPE_P(other)) {
return DBL2NUM(nurat_to_double(self) * RFLOAT_VALUE(other));
}
else if (RB_TYPE_P(other, T_RATIONAL)) {
{
get_dat2(self, other);

return f_muldiv(self,
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) && RB_INTEGER_TYPE_P(other)) {
return f_rational_new_bang1(CLASS_OF(self), INT2FIX(f_odd_p(other) ? -1 : 1));
}
else if (INT_ZERO_P(dat->num)) {
if (rb_num_negative_p(other)) {
rb_num_zerodiv();
}
else {
return f_rational_new_bang1(CLASS_OF(self), ZERO);
}
}
}
}

/* General case */
if (FIXNUM_P(other)) {
{
VALUE num, den;

get_dat1(self);

if (INT_POSITIVE_P(other)) {
num = rb_int_pow(dat->num, other);
den = rb_int_pow(dat->den, other);
}
else if (INT_NEGATIVE_P(other)) {
num = rb_int_pow(dat->den, rb_int_uminus(other));
den = rb_int_pow(dat->num, rb_int_uminus(other));
}
else {
num = ONE;
den = ONE;
}
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 rb_float_pow(nurat_to_f(self), other);
}
else if (RB_FLOAT_TYPE_P(other) || RB_TYPE_P(other, T_RATIONAL)) {
return rb_float_pow(nurat_to_f(self), other);
}
else {
return rb_num_coerce_bin(self, other, rb_intern("**"));
}
}```
rat + numeric → numeric click to toggle source

```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
```
```VALUE
rb_rational_plus(VALUE self, VALUE other)
{
if (RB_INTEGER_TYPE_P(other)) {
{
get_dat1(self);

return f_rational_new_no_reduce2(CLASS_OF(self),
rb_int_plus(dat->num, rb_int_mul(other, dat->den)),
dat->den);
}
}
else if (RB_FLOAT_TYPE_P(other)) {
return DBL2NUM(nurat_to_double(self) + RFLOAT_VALUE(other));
}
else if (RB_TYPE_P(other, T_RATIONAL)) {
{
get_dat2(self, other);

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_INTEGER_TYPE_P(other)) {
{
get_dat1(self);

return f_rational_new_no_reduce2(CLASS_OF(self),
rb_int_minus(dat->num, rb_int_mul(other, dat->den)),
dat->den);
}
}
else if (RB_FLOAT_TYPE_P(other)) {
return DBL2NUM(nurat_to_double(self) - RFLOAT_VALUE(other));
}
else if (RB_TYPE_P(other, T_RATIONAL)) {
{
get_dat2(self, other);

bdat->num, bdat->den, '-');
}
}
else {
return rb_num_coerce_bin(self, other, '-');
}
}```
-rat → rational click to toggle source

Negates `rat`.

```VALUE
rb_rational_uminus(VALUE self)
{
const int unused = (assert(RB_TYPE_P(self, T_RATIONAL)), 0);
get_dat1(self);
(void)unused;
return f_rational_new2(CLASS_OF(self), rb_int_uminus(dat->num), dat->den);
}```
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_INTEGER_TYPE_P(other)) {
if (f_zero_p(other))
rb_num_zerodiv();
{
get_dat1(self);

return f_muldiv(self,
dat->num, dat->den,
other, ONE, '/');
}
}
else if (RB_FLOAT_TYPE_P(other))
return DBL2NUM(nurat_to_double(self) / RFLOAT_VALUE(other));
else if (RB_TYPE_P(other, T_RATIONAL)) {
if (f_zero_p(other))
rb_num_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,
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
```
```VALUE
rb_rational_cmp(VALUE self, VALUE other)
{
if (RB_INTEGER_TYPE_P(other)) {
{
get_dat1(self);

if (dat->den == LONG2FIX(1))
return rb_int_cmp(dat->num, other); /* c14n */
other = f_rational_new_bang1(CLASS_OF(self), other);
goto other_is_rational;
}
}
else if (RB_FLOAT_TYPE_P(other)) {
return rb_dbl_cmp(nurat_to_double(self), RFLOAT_VALUE(other));
}
else if (RB_TYPE_P(other, T_RATIONAL)) {
other_is_rational:
{
VALUE num1, num2;

get_dat2(self, other);

FIXNUM_P(bdat->num) && FIXNUM_P(bdat->den)) {
}
else {
}
return rb_int_cmp(rb_int_minus(num1, num2), ZERO);
}
}
else {
return rb_num_coerce_cmp(self, other, rb_intern("<=>"));
}
}```
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_INTEGER_TYPE_P(other)) {
{
get_dat1(self);

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

if (!FIXNUM_P(dat->den))
return Qfalse;
if (FIX2LONG(dat->den) != 1)
return Qfalse;
return rb_int_equal(dat->num, other);
}
}
else if (RB_FLOAT_TYPE_P(other)) {
const double d = nurat_to_double(self);
return f_boolcast(FIXNUM_ZERO_P(rb_dbl_cmp(d, RFLOAT_VALUE(other))));
}
else if (RB_TYPE_P(other, T_RATIONAL)) {
{
get_dat2(self, other);

return Qtrue;

}
}
else {
return rb_equal(other, self);
}
}```
abs → rat click to toggle source

Returns the absolute value of `rat`.

```(1/2r).abs    #=> 1/2r
(-1/2r).abs   #=> 1/2r
```

`Rational#magnitude` is an alias of `Rational#abs`.

```VALUE
rb_rational_abs(VALUE self)
{
get_dat1(self);
if (INT_NEGATIVE_P(dat->num)) {
VALUE num = rb_int_abs(dat->num);
return nurat_s_canonicalize_internal_no_reduce(CLASS_OF(self), num, dat->den);
}
return self;
}```
as_json(*) click to toggle source

Returns a hash, that will be turned into a `JSON` object and represent this object.

```# File ext/json/lib/json/add/rational.rb, line 16
def as_json(*)
{
JSON.create_id => self.class.name,
'n'            => numerator,
'd'            => denominator,
}
end```
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)
{
VALUE div;
if (f_zero_p(other))
return DBL2NUM(nurat_to_double(self) / 0.0);
if (FIXNUM_P(other) && other == LONG2FIX(1))
return nurat_to_f(self);
div = nurat_div(self, other);
if (RB_TYPE_P(div, T_RATIONAL))
return nurat_to_f(div);
if (RB_FLOAT_TYPE_P(div))
return div;
return rb_funcall(div, rb_intern("to_f"), 0);
}```
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;
}```
magnitude → rat click to toggle source

Returns the absolute value of `rat`.

```(1/2r).abs    #=> 1/2r
(-1/2r).abs   #=> 1/2r
```

`Rational#magnitude` is an alias of `Rational#abs`.

```VALUE
rb_rational_abs(VALUE self)
{
get_dat1(self);
if (INT_NEGATIVE_P(dat->num)) {
VALUE num = rb_int_abs(dat->num);
return nurat_s_canonicalize_internal_no_reduce(CLASS_OF(self), num, dat->den);
}
return self;
}```
negative? → true or false click to toggle source

Returns `true` if `rat` is less than 0.

```static VALUE
nurat_negative_p(VALUE self)
{
get_dat1(self);
return f_boolcast(INT_NEGATIVE_P(dat->num));
}```
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;
}```
positive? → true or false click to toggle source

Returns `true` if `rat` is greater than 0.

```static VALUE
nurat_positive_p(VALUE self)
{
get_dat1(self);
return f_boolcast(INT_POSITIVE_P(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_INTEGER_TYPE_P(other)) {
if (f_zero_p(other))
rb_num_zerodiv();
{
get_dat1(self);

return f_muldiv(self,
dat->num, dat->den,
other, ONE, '/');
}
}
else if (RB_FLOAT_TYPE_P(other))
return DBL2NUM(nurat_to_double(self) / RFLOAT_VALUE(other));
else if (RB_TYPE_P(other, T_RATIONAL)) {
if (f_zero_p(other))
rb_num_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,
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 (nurat_negative_p(self))
return rb_rational_uminus(nurat_rationalize(argc, argv, rb_rational_uminus(self)));

rb_scan_args(argc, argv, "01", &e);
e = f_abs(e);
a = f_sub(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)
{
VALUE opt;
enum ruby_num_rounding_mode mode = (
argc = rb_scan_args(argc, argv, "*:", NULL, &opt),
rb_num_get_rounding_option(opt));
VALUE (*round_func)(VALUE) = ROUND_FUNC(mode, nurat_round);
return f_round_common(argc, argv, self, round_func);
}```
to_d(precision) → bigdecimal click to toggle source

Returns the value as a `BigDecimal`.

The required `precision` parameter is used to determine the number of significant digits for the result.

```require 'bigdecimal'
require 'bigdecimal/util'

Rational(22, 7).to_d(3)   # => 0.314e1
```

See also `BigDecimal::new`.

```# File ext/bigdecimal/lib/bigdecimal/util.rb, line 131
def to_d(precision)
BigDecimal(self, precision)
end```
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)
{
return DBL2NUM(nurat_to_double(self));
}```
to_i → integer click to toggle source

Returns the truncated value as an integer.

Equivalent to `Rational#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 (INT_NEGATIVE_P(dat->num))
return rb_int_uminus(rb_int_idiv(rb_int_uminus(dat->num), dat->den));
return rb_int_idiv(dat->num, dat->den);
}```
to_json(*) click to toggle source

Stores class name (`Rational`) along with numerator value `n` and denominator value `d` as `JSON` string

```# File ext/json/lib/json/add/rational.rb, line 25
def to_json(*)
as_json.to_json
end```
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);
}```