Ruby 2.4

Rational

class Rational

BigDecimal扩展了本地Rational类以提供to_d方法。

当您在应用程序中需要BigDecimal时,此方法将在Rational对象上可用。

一个有理数可以表示成一个成对的整数; a / b(b> 0)。a是分子,b是分母。整数等于理性a / 1在数学上。

在ruby中,您可以使用Rational创建合理的对象,#to_r,合理化方法或将r后缀到文字。返回值将是不可减少的。

Rational(1) #=> (1/1) Rational(2, 3) #=> (2/3) Rational(4, -6) #=> (-2/3) 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)

公共类方法

json_create(object) Show source

通过将分子值n分母值d转换为Rational对象来反序列化JSON字符串。

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

公共实例方法

rat * numeric → numeric Show source

执行乘法。

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, adat->num, adat->den, bdat->num, bdat->den, '*' } } else { return rb_num_coerce_bin(self, other, '*' } }

rat ** numeric → numeric Show source

执行取幂。

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 Show 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 return f_addsub(self, adat->num, adat->den, bdat->num, bdat->den, '+' } } else { return rb_num_coerce_bin(self, other, '+' } }

rat - numeric → numeric Show source

执行减法。

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 return f_addsub(self, adat->num, adat->den, bdat->num, bdat->den, '-' } } else { return rb_num_coerce_bin(self, other, '-' } }

-rat → rational Show source

否定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 Show source

执行除法。

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, adat->num, adat->den, bdat->num, bdat->den, '/' } } else { return rb_num_coerce_bin(self, other, '/' } }

rational <=> numeric → -1, 0, +1 or nil Show source

执行比较并返回-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

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 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 } } else { return rb_num_coerce_cmp(self, other, rb_intern("<=>") } }

鼠标==对象→true或false显示源代码

如果鼠数等于对象,则返回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

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 if (INT_ZERO_P(adat->num) && INT_ZERO_P(bdat->num)) return Qtrue; return f_boolcast(rb_int_equal(adat->num, bdat->num) && rb_int_equal(adat->den, bdat->den) } } else { return rb_equal(other, self } }

abs → rat Show source

返回的绝对值rat

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

#magnitude是#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(*) Show source

返回一个散列,它将变成一个JSON对象并表示这个对象。

# 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 Show source

ceil(precision=0) → rational

返回截断值(朝正无穷大)。

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 Show source

返回分母(总是正数)。

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 Show source

执行除法并将其作为浮点值返回。

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 Show source

floor(precision=0) → rational

返回截断值(朝负无穷大)。

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 Show source

将该值作为字符串返回以进行检查。

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 Show source

返回的绝对值rat

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

#magnitude is an alias of #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 Show source

返回trueif rat小于0。

static VALUE nurat_negative_p(VALUE self) { get_dat1(self return f_boolcast(INT_NEGATIVE_P(dat->num) }

numerator → integer Show source

返回分子。

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

正?→true或false显示来源

true如果rat大于0,则返回。

static VALUE nurat_positive_p(VALUE self) { get_dat1(self return f_boolcast(INT_POSITIVE_P(dat->num) }

quo(numeric) → numeric Show source

执行除法。

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, adat->num, adat->den, bdat->num, bdat->den, '/' } } else { return rb_num_coerce_bin(self, other, '/' } }

rationalize → self Show source

rationalize(eps) → rational

如果给出可选参数eps(rat- | eps | <= result <= 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_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 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 Show source

round(precision=0) → rational

返回截断值(朝向最接近的整数; 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 Show source

将Rational转换为BigDecimal。

所需的precision参数用于确定结果的有效位数。请参阅BigDecimal#div以获取更多信息,因为它与分母和precisionfor参数一起使用。

r = (22/7.0).to_r # => (7077085128725065/2251799813685248) r.to_d(3) # => 0.314e1

# File ext/bigdecimal/lib/bigdecimal/util.rb, line 120 def to_d(precision) if precision <= 0 raise ArgumentError, "negative precision" end num = self.numerator BigDecimal(num).div(self.denominator, precision) end

to_f → float Show source

以浮点形式返回值。

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 Show source

以整数形式返回截断的值。

相当于

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 (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(*) Show source

将类名(Rational)与分子值n和分母值一起存储d为JSON字符串

# File ext/json/lib/json/add/rational.rb, line 25 def to_json(*) as_json.to_json end

to_r → self Show 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 Show source

以字符串形式返回值。

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 Show source

truncate(precision=0) → rational

返回截断值(趋近于零)。

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 }