class Rational
有理数可以用一对整数表示:a/b (b>0),其中 a 是分子,b 是分母。 数学上,Integer a 等于有理数 a/1。
您可以使用以下方式显式创建 Rational 对象:
您可以使用以下方式将某些对象转换为有理数:
- 
Rational方法。
示例
Rational(1) #=> (1/1) Rational(2, 3) #=> (2/3) Rational(4, -6) #=> (-2/3) # Reduced. 3.to_r #=> (3/1) 2/3r #=> (2/3)
您还可以从浮点数或字符串创建有理数对象。
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)
有理数对象是一个精确的数字,它可以帮助您编写没有任何舍入误差的程序。
10.times.inject(0) {|t| t + 0.1 } #=> 0.9999999999999999 10.times.inject(0) {|t| t + Rational('0.1') } #=> (1/1)
但是,当表达式包含不精确的组成部分(数值或运算)时,它将产生不精确的结果。
Rational(10) / 3 #=> (10/3) Rational(10) / 3.0 #=> 3.3333333333333335 Rational(-8) ** Rational(1, 3) #=> (1.0000000000000002+1.7320508075688772i)
公共类方法
源代码
# File ext/json/lib/json/add/rational.rb, line 9 def self.json_create(object) Rational(object['n'], object['d']) end
请参阅 as_json。
公共实例方法
源代码
VALUE
rb_rational_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,
                            adat->num, adat->den,
                            bdat->num, bdat->den, '*');
        }
    }
    else {
        return rb_num_coerce_bin(self, other, '*');
    }
}
          执行乘法运算。
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
源代码
VALUE
rb_rational_pow(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(rb_int_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_BIGNUM_TYPE_P(other)) {
        rb_raise(rb_eArgError, "exponent is too large");
    }
    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, idPow);
    }
}
          执行幂运算。
Rational(2) ** Rational(3) #=> (8/1) Rational(10) ** -2 #=> (1/100) Rational(10) ** -2.0 #=> 0.01 Rational(-4) ** Rational(1, 2) #=> (0.0+2.0i) Rational(1, 2) ** 0 #=> (1/1) Rational(1, 2) ** 0.0 #=> 1.0
源代码
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);
            return f_addsub(self,
                            adat->num, adat->den,
                            bdat->num, bdat->den, '+');
        }
    }
    else {
        return rb_num_coerce_bin(self, other, '+');
    }
}
          执行加法运算。
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_minus(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);
            return f_addsub(self,
                            adat->num, adat->den,
                            bdat->num, bdat->den, '-');
        }
    }
    else {
        return rb_num_coerce_bin(self, other, '-');
    }
}
          执行减法运算。
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
源代码
VALUE
rb_rational_uminus(VALUE self)
{
    const int unused = (RUBY_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 的负值。
源代码
VALUE
rb_rational_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)) {
        VALUE v = nurat_to_f(self);
        return rb_flo_div_flo(v, 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,
                            adat->num, adat->den,
                            bdat->num, bdat->den, '/');
        }
    }
    else {
        return rb_num_coerce_bin(self, other, '/');
    }
}
          执行除法运算。
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
源代码
VALUE
rb_rational_cmp(VALUE self, VALUE other)
{
    switch (TYPE(other)) {
      case T_FIXNUM:
      case T_BIGNUM:
        {
            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);
            /* FALLTHROUGH */
        }
      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 = rb_int_mul(adat->num, bdat->den);
                num2 = rb_int_mul(bdat->num, adat->den);
            }
            return rb_int_cmp(rb_int_minus(num1, num2), ZERO);
        }
      case T_FLOAT:
        return rb_dbl_cmp(nurat_to_double(self), RFLOAT_VALUE(other));
      default:
        return rb_num_coerce_cmp(self, other, idCmp);
    }
}
          根据 rational 小于、等于还是大于 numeric,返回 -1、0 或 +1。
如果两个值无法比较,则返回 nil。
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 Rational(1, 3) <=> "0.3" #=> nil
源代码
static VALUE
nurat_eqeq_p(VALUE self, VALUE other)
{
    if (RB_INTEGER_TYPE_P(other)) {
        get_dat1(self);
        if (RB_INTEGER_TYPE_P(dat->num) && RB_INTEGER_TYPE_P(dat->den)) {
            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 {
            const double d = nurat_to_double(self);
            return RBOOL(FIXNUM_ZERO_P(rb_dbl_cmp(d, NUM2DBL(other))));
        }
    }
    else if (RB_FLOAT_TYPE_P(other)) {
        const double d = nurat_to_double(self);
        return RBOOL(FIXNUM_ZERO_P(rb_dbl_cmp(d, RFLOAT_VALUE(other))));
    }
    else if (RB_TYPE_P(other, T_RATIONAL)) {
        {
            get_dat2(self, other);
            if (INT_ZERO_P(adat->num) && INT_ZERO_P(bdat->num))
                return Qtrue;
            return RBOOL(rb_int_equal(adat->num, bdat->num) &&
                              rb_int_equal(adat->den, bdat->den));
        }
    }
    else {
        return rb_equal(other, self);
    }
}
          如果 rat 在数值上等于 object,则返回 true。
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
源代码
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;
}
          返回 rat 的绝对值。
(1/2r).abs #=> (1/2) (-1/2r).abs #=> (1/2)
源代码
# File ext/json/lib/json/add/rational.rb, line 29 def as_json(*) { JSON.create_id => self.class.name, 'n' => numerator, 'd' => denominator, } end
方法 Rational#as_json 和 Rational.json_create 可用于序列化和反序列化 Rational 对象;请参阅 Marshal。
方法 Rational#as_json 序列化 self,返回一个包含 2 个元素的哈希,表示 self
require 'json/add/rational' x = Rational(2, 3).as_json # => {"json_class"=>"Rational", "n"=>2, "d"=>3}
方法 JSON.create 反序列化这样的哈希,返回一个 Rational 对象
Rational.json_create(x) # => (2/3)
源代码
static VALUE
nurat_ceil_n(int argc, VALUE *argv, VALUE self)
{
    return f_round_common(argc, argv, self, nurat_ceil);
}
          返回大于或等于 rat 的最小数,精度为 ndigits 位小数(默认值:0)。
当精度为负数时,返回的值是一个整数,至少有 ndigits.abs 个尾随零。
当 ndigits 为正数时,返回有理数,否则返回整数。
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 Rational('-123.456').ceil(+1).to_f #=> -123.4 Rational('-123.456').ceil(-1) #=> -120
源代码
static VALUE
nurat_denominator(VALUE self)
{
    get_dat1(self);
    return dat->den;
}
          返回分母(始终为正数)。
Rational(7).denominator #=> 1 Rational(7, 1).denominator #=> 1 Rational(9, -4).denominator #=> 4 Rational(-2, -10).denominator #=> 5
源代码
static VALUE
nurat_fdiv(VALUE self, VALUE other)
{
    VALUE div;
    if (f_zero_p(other))
        return rb_rational_div(self, rb_float_new(0.0));
    if (FIXNUM_P(other) && other == LONG2FIX(1))
        return nurat_to_f(self);
    div = rb_rational_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, idTo_f, 0);
}
          执行除法运算,并以 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_floor_n(int argc, VALUE *argv, VALUE self)
{
    return f_round_common(argc, argv, self, nurat_floor);
}
          返回小于或等于 rat 的最大数,精度为 ndigits 位小数(默认值:0)。
当精度为负数时,返回的值是一个整数,至少有 ndigits.abs 个尾随零。
当 ndigits 为正数时,返回有理数,否则返回整数。
Rational(3).floor #=> 3 Rational(2, 3).floor #=> 0 Rational(-3, 2).floor #=> -2 # decimal - 1 2 3 . 4 5 6 # ^ ^ ^ ^ ^ ^ # precision -3 -2 -1 0 +1 +2 Rational('-123.456').floor(+1).to_f #=> -123.5 Rational('-123.456').floor(-1) #=> -130
源代码
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;
}
          以字符串形式返回用于检查的值。
Rational(2).inspect #=> "(2/1)" Rational(-8, 6).inspect #=> "(-4/3)" Rational('1/2').inspect #=> "(1/2)"
源代码
static VALUE
nurat_negative_p(VALUE self)
{
    get_dat1(self);
    return RBOOL(INT_NEGATIVE_P(dat->num));
}
          如果 rat 小于 0,则返回 true。
源代码
static VALUE
nurat_numerator(VALUE self)
{
    get_dat1(self);
    return dat->num;
}
          返回分子。
Rational(7).numerator #=> 7 Rational(7, 1).numerator #=> 7 Rational(9, -4).numerator #=> -9 Rational(-2, -10).numerator #=> 1
源代码
static VALUE
nurat_positive_p(VALUE self)
{
    get_dat1(self);
    return RBOOL(INT_POSITIVE_P(dat->num));
}
          如果 rat 大于 0,则返回 true。
执行除法运算。
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_rationalize(int argc, VALUE *argv, VALUE self)
{
    VALUE e, a, b, p, q;
    VALUE rat = self;
    get_dat1(self);
    if (rb_check_arity(argc, 0, 1) == 0)
        return self;
    e = f_abs(argv[0]);
    if (INT_NEGATIVE_P(dat->num)) {
        rat = f_rational_new2(RBASIC_CLASS(self), rb_int_uminus(dat->num), dat->den);
    }
    a = FIXNUM_ZERO_P(e) ? rat : rb_rational_minus(rat, e);
    b = FIXNUM_ZERO_P(e) ? rat : rb_rational_plus(rat, e);
    if (f_eqeq_p(a, b))
        return self;
    nurat_rationalize_internal(a, b, &p, &q);
    if (rat != self) {
        RATIONAL_SET_NUM(rat, rb_int_uminus(p));
        RATIONAL_SET_DEN(rat, q);
        return rat;
    }
    return f_rational_new2(CLASS_OF(self), p, q);
}
          如果给定了可选参数 eps,则返回该值的更简单的近似值(rat-|eps| <= 结果 <= rat+|eps|),否则返回 self。
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_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);
}
          返回 rat 四舍五入到最接近的值,精度为 ndigits 位小数(默认值:0)。
当精度为负数时,返回的值是一个整数,至少有 ndigits.abs 个尾随零。
当 ndigits 为正数时,返回有理数,否则返回整数。
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 Rational('-123.456').round(+1).to_f #=> -123.5 Rational('-123.456').round(-1) #=> -120
可选的 half 关键字参数的使用方式类似于 Float#round。
Rational(25, 100).round(1, half: :up) #=> (3/10) Rational(25, 100).round(1, half: :down) #=> (1/5) Rational(25, 100).round(1, half: :even) #=> (1/5) Rational(35, 100).round(1, half: :up) #=> (2/5) Rational(35, 100).round(1, half: :down) #=> (3/10) Rational(35, 100).round(1, half: :even) #=> (2/5) Rational(-25, 100).round(1, half: :up) #=> (-3/10) Rational(-25, 100).round(1, half: :down) #=> (-1/5) Rational(-25, 100).round(1, half: :even) #=> (-1/5)
源代码
static VALUE
nurat_to_f(VALUE self)
{
    return DBL2NUM(nurat_to_double(self));
}
          以 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_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);
}
          以整数形式返回截断的值。
等同于 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(-31, 2).to_i #=> -15
源代码
# File ext/json/lib/json/add/rational.rb, line 46 def to_json(*args) as_json.to_json(*args) end
返回表示 self 的 JSON 字符串
require 'json/add/rational' puts Rational(2, 3).to_json
输出
{"json_class":"Rational","n":2,"d":3}
        源代码
static VALUE
nurat_to_r(VALUE self)
{
    return self;
}
          返回 self。
Rational(2).to_r #=> (2/1) Rational(-8, 6).to_r #=> (-4/3)
源代码
static VALUE
nurat_to_s(VALUE self)
{
    return f_format(self, f_to_s);
}
          以字符串形式返回值。
Rational(2).to_s #=> "2/1" Rational(-8, 6).to_s #=> "-4/3" Rational('1/2').to_s #=> "1/2"
源代码
static VALUE
nurat_truncate_n(int argc, VALUE *argv, VALUE self)
{
    return f_round_common(argc, argv, self, nurat_truncate);
}
          返回 rat 截断(向零方向)到精度为 ndigits 位小数(默认值:0)。
当精度为负数时,返回的值是一个整数,至少有 ndigits.abs 个尾随零。
当 ndigits 为正数时,返回有理数,否则返回整数。
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 Rational('-123.456').truncate(+1).to_f #=> -123.4 Rational('-123.456').truncate(-1) #=> -120