Feature #12484 » 0002-optimize-Rational-methods.patch
rational.c | ||
---|---|---|
#define GMP_GCD_DIGITS 1
|
||
#define INT_POSITIVE_P(x) (FIXNUM_P(x) ? ((SIGNED_VALUE)(x) > (SIGNED_VALUE)INT2FIX(0)) : BIGNUM_POSITIVE_P(x))
|
||
#define INT_NEGATIVE_P(x) (FIXNUM_P(x) ? ((SIGNED_VALUE)(x) < 0) : BIGNUM_NEGATIVE_P(x))
|
||
#define INT_ZERO_P(x) (FIXNUM_P(x) ? (FIX2LONG(x) == 0) : rb_bigzero_p(x))
|
||
VALUE rb_cRational;
|
||
static ID id_abs, id_cmp, id_convert, id_eqeq_p, id_expt, id_fdiv,
|
||
id_idiv, id_integer_p, id_negate, id_to_f,
|
||
id_to_i, id_truncate, id_i_num, id_i_den;
|
||
static ID id_abs, id_eqeq_p, id_idiv, id_integer_p, id_negate, id_to_i,
|
||
id_i_num, id_i_den;
|
||
#define f_boolcast(x) ((x) ? Qtrue : Qfalse)
|
||
#define f_inspect rb_inspect
|
||
... | ... | |
}
|
||
inline static VALUE
|
||
f_cmp(VALUE x, VALUE y)
|
||
{
|
||
if (FIXNUM_P(x) && FIXNUM_P(y)) {
|
||
long c = FIX2LONG(x) - FIX2LONG(y);
|
||
if (c > 0)
|
||
c = 1;
|
||
else if (c < 0)
|
||
c = -1;
|
||
return INT2FIX(c);
|
||
}
|
||
return rb_funcall(x, id_cmp, 1, y);
|
||
}
|
||
inline static VALUE
|
||
f_div(VALUE x, VALUE y)
|
||
{
|
||
if (FIXNUM_P(y) && FIX2LONG(y) == 1)
|
||
return x;
|
||
if (FIXNUM_P(x) || RB_TYPE_P(x, T_BIGNUM))
|
||
return rb_int_div(x, y);
|
||
return rb_funcall(x, '/', 1, y);
|
||
}
|
||
... | ... | |
}
|
||
else if (ix == 1)
|
||
return y;
|
||
return rb_int_mul(x, y);
|
||
}
|
||
else if (RB_TYPE_P(x, T_BIGNUM))
|
||
return rb_int_mul(x, y);
|
||
return rb_funcall(x, '*', 1, y);
|
||
}
|
||
... | ... | |
return rb_funcall(x, '-', 1, y);
|
||
}
|
||
fun1(abs)
|
||
inline static VALUE
|
||
f_abs(VALUE x)
|
||
{
|
||
if (FIXNUM_P(x) || RB_TYPE_P(x, T_BIGNUM))
|
||
return rb_int_abs(x);
|
||
return rb_funcall(x, id_abs, 0);
|
||
}
|
||
fun1(integer_p)
|
||
fun1(negate)
|
||
... | ... | |
return rb_str_to_inum(x, 10, 0);
|
||
return rb_funcall(x, id_to_i, 0);
|
||
}
|
||
inline static VALUE
|
||
f_to_f(VALUE x)
|
||
{
|
||
if (RB_TYPE_P(x, T_STRING))
|
||
return DBL2NUM(rb_str_to_dbl(x, 0));
|
||
return rb_funcall(x, id_to_f, 0);
|
||
}
|
||
inline static VALUE
|
||
f_eqeq_p(VALUE x, VALUE y)
|
||
... | ... | |
return rb_funcall(x, id_eqeq_p, 1, y);
|
||
}
|
||
fun2(expt)
|
||
fun2(fdiv)
|
||
fun2(idiv)
|
||
#define f_expt10(x) f_expt(INT2FIX(10), x)
|
||
inline static VALUE
|
||
f_negative_p(VALUE x)
|
||
{
|
||
if (FIXNUM_P(x))
|
||
return f_boolcast(FIX2LONG(x) < 0);
|
||
return rb_funcall(x, '<', 1, ZERO);
|
||
}
|
||
#define f_positive_p(x) (!f_negative_p(x))
|
||
#define f_expt10(x) rb_int_pow(INT2FIX(10), x)
|
||
inline static VALUE
|
||
f_zero_p(VALUE x)
|
||
... | ... | |
if (FIXNUM_P(x) && FIXNUM_P(y))
|
||
return LONG2NUM(i_gcd(FIX2LONG(x), FIX2LONG(y)));
|
||
if (f_negative_p(x))
|
||
x = f_negate(x);
|
||
if (f_negative_p(y))
|
||
y = f_negate(y);
|
||
if (INT_NEGATIVE_P(x))
|
||
x = rb_int_uminus(x);
|
||
if (INT_NEGATIVE_P(y))
|
||
y = rb_int_uminus(y);
|
||
if (f_zero_p(x))
|
||
if (INT_ZERO_P(x))
|
||
return y;
|
||
if (f_zero_p(y))
|
||
if (INT_ZERO_P(y))
|
||
return x;
|
||
for (;;) {
|
||
... | ... | |
return LONG2NUM(i_gcd(FIX2LONG(x), FIX2LONG(y)));
|
||
}
|
||
z = x;
|
||
x = f_mod(y, x);
|
||
x = rb_int_modulo(y, x);
|
||
y = z;
|
||
}
|
||
/* NOTREACHED */
|
||
... | ... | |
inline static VALUE
|
||
f_lcm(VALUE x, VALUE y)
|
||
{
|
||
if (f_zero_p(x) || f_zero_p(y))
|
||
if (INT_ZERO_P(x) || INT_ZERO_P(y))
|
||
return ZERO;
|
||
return f_abs(f_mul(f_div(x, f_gcd(x, y)), y));
|
||
}
|
||
... | ... | |
return nurat_s_new_internal(klass, ZERO, ONE);
|
||
}
|
||
#define rb_raise_zerodiv() rb_raise(rb_eZeroDivError, "divided by 0")
|
||
#if 0
|
||
static VALUE
|
||
nurat_s_new_bang(int argc, VALUE *argv, VALUE klass)
|
||
... | ... | |
if (!k_integer_p(den))
|
||
den = f_to_i(den);
|
||
switch (FIX2INT(f_cmp(den, ZERO))) {
|
||
switch (FIX2INT(rb_int_cmp(den, ZERO))) {
|
||
case -1:
|
||
num = f_negate(num);
|
||
den = f_negate(den);
|
||
break;
|
||
case 0:
|
||
rb_raise_zerodiv();
|
||
rb_num_zerodiv();
|
||
break;
|
||
}
|
||
break;
|
||
... | ... | |
{
|
||
VALUE gcd;
|
||
switch (FIX2INT(f_cmp(den, ZERO))) {
|
||
switch (FIX2INT(rb_int_cmp(den, ZERO))) {
|
||
case -1:
|
||
num = f_negate(num);
|
||
den = f_negate(den);
|
||
break;
|
||
case 0:
|
||
rb_raise_zerodiv();
|
||
rb_num_zerodiv();
|
||
break;
|
||
}
|
||
... | ... | |
inline static VALUE
|
||
nurat_s_canonicalize_internal_no_reduce(VALUE klass, VALUE num, VALUE den)
|
||
{
|
||
switch (FIX2INT(f_cmp(den, ZERO))) {
|
||
switch (FIX2INT(rb_int_cmp(den, ZERO))) {
|
||
case -1:
|
||
num = f_negate(num);
|
||
den = f_negate(den);
|
||
break;
|
||
case 0:
|
||
rb_raise_zerodiv();
|
||
rb_num_zerodiv();
|
||
break;
|
||
}
|
||
... | ... | |
return nurat_s_canonicalize_internal_no_reduce(klass, x, y);
|
||
}
|
||
static VALUE nurat_s_convert(int argc, VALUE *argv, VALUE klass);
|
||
/*
|
||
* call-seq:
|
||
* Rational(x[, y]) -> numeric
|
||
... | ... | |
static VALUE
|
||
nurat_f_rational(int argc, VALUE *argv, VALUE klass)
|
||
{
|
||
return rb_funcall2(rb_cRational, id_convert, argc, argv);
|
||
return nurat_s_convert(argc, argv, rb_cRational);
|
||
}
|
||
/*
|
||
... | ... | |
return dat->den;
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* -rat -> rational
|
||
*
|
||
* Negates +rat+.
|
||
*/
|
||
static VALUE
|
||
nurat_negate(VALUE self)
|
||
{
|
||
get_dat1(self);
|
||
return f_rational_new2(CLASS_OF(self), rb_int_uminus(dat->num), dat->den);
|
||
}
|
||
#ifndef NDEBUG
|
||
#define f_imul f_imul_orig
|
||
#endif
|
||
... | ... | |
VALUE c;
|
||
if (k == '+')
|
||
c = f_add(a, b);
|
||
c = rb_int_plus(a, b);
|
||
else
|
||
c = f_sub(a, b);
|
||
c = rb_int_minus(a, b);
|
||
b = f_idiv(aden, g);
|
||
b = rb_int_idiv(aden, g);
|
||
g = f_gcd(c, g);
|
||
num = f_idiv(c, g);
|
||
a = f_idiv(bden, g);
|
||
den = f_mul(a, b);
|
||
num = rb_int_idiv(c, g);
|
||
a = rb_int_idiv(bden, g);
|
||
den = rb_int_mul(a, b);
|
||
}
|
||
else {
|
||
VALUE g = f_gcd(aden, bden);
|
||
VALUE a = f_mul(anum, f_idiv(bden, g));
|
||
VALUE b = f_mul(bnum, f_idiv(aden, g));
|
||
VALUE a = rb_int_mul(anum, rb_int_idiv(bden, g));
|
||
VALUE b = rb_int_mul(bnum, rb_int_idiv(aden, g));
|
||
VALUE c;
|
||
if (k == '+')
|
||
c = f_add(a, b);
|
||
c = rb_int_plus(a, b);
|
||
else
|
||
c = f_sub(a, b);
|
||
c = rb_int_minus(a, b);
|
||
b = f_idiv(aden, g);
|
||
b = rb_int_idiv(aden, g);
|
||
g = f_gcd(c, g);
|
||
num = f_idiv(c, g);
|
||
a = f_idiv(bden, g);
|
||
den = f_mul(a, b);
|
||
num = rb_int_idiv(c, g);
|
||
a = rb_int_idiv(bden, g);
|
||
den = rb_int_mul(a, b);
|
||
}
|
||
return f_rational_new_no_reduce2(CLASS_OF(self), num, den);
|
||
}
|
||
static VALUE nurat_to_f(VALUE self);
|
||
/*
|
||
* call-seq:
|
||
* rat + numeric -> numeric
|
||
... | ... | |
{
|
||
get_dat1(self);
|
||
return f_addsub(self,
|
||
dat->num, dat->den,
|
||
other, ONE, '+');
|
||
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_TYPE_P(other, T_FLOAT)) {
|
||
return f_add(f_to_f(self), other);
|
||
return DBL2NUM(RFLOAT_VALUE(nurat_to_f(self)) + RFLOAT_VALUE(other));
|
||
}
|
||
else if (RB_TYPE_P(other, T_RATIONAL)) {
|
||
{
|
||
... | ... | |
{
|
||
get_dat1(self);
|
||
return f_addsub(self,
|
||
dat->num, dat->den,
|
||
other, ONE, '-');
|
||
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_TYPE_P(other, T_FLOAT)) {
|
||
return f_sub(f_to_f(self), other);
|
||
return DBL2NUM(RFLOAT_VALUE(nurat_to_f(self)) - RFLOAT_VALUE(other));
|
||
}
|
||
else if (RB_TYPE_P(other, T_RATIONAL)) {
|
||
{
|
||
... | ... | |
if (k == '/') {
|
||
VALUE t;
|
||
if (f_negative_p(bnum)) {
|
||
anum = f_negate(anum);
|
||
bnum = f_negate(bnum);
|
||
if (INT_NEGATIVE_P(bnum)) {
|
||
anum = rb_int_uminus(anum);
|
||
bnum = rb_int_uminus(bnum);
|
||
}
|
||
t = bnum;
|
||
bnum = bden;
|
||
... | ... | |
VALUE g1 = f_gcd(anum, bden);
|
||
VALUE g2 = f_gcd(aden, bnum);
|
||
num = f_mul(f_idiv(anum, g1), f_idiv(bnum, g2));
|
||
den = f_mul(f_idiv(aden, g2), f_idiv(bden, g1));
|
||
num = rb_int_mul(rb_int_idiv(anum, g1), rb_int_idiv(bnum, g2));
|
||
den = rb_int_mul(rb_int_idiv(aden, g2), rb_int_idiv(bden, g1));
|
||
}
|
||
return f_rational_new_no_reduce2(CLASS_OF(self), num, den);
|
||
}
|
||
... | ... | |
}
|
||
}
|
||
else if (RB_TYPE_P(other, T_FLOAT)) {
|
||
return f_mul(f_to_f(self), other);
|
||
return DBL2NUM(RFLOAT_VALUE(nurat_to_f(self)) * RFLOAT_VALUE(other));
|
||
}
|
||
else if (RB_TYPE_P(other, T_RATIONAL)) {
|
||
{
|
||
... | ... | |
{
|
||
if (RB_TYPE_P(other, T_FIXNUM) || RB_TYPE_P(other, T_BIGNUM)) {
|
||
if (f_zero_p(other))
|
||
rb_raise_zerodiv();
|
||
rb_num_zerodiv();
|
||
{
|
||
get_dat1(self);
|
||
... | ... | |
}
|
||
}
|
||
else if (RB_TYPE_P(other, T_FLOAT))
|
||
return rb_funcall(f_to_f(self), '/', 1, other);
|
||
return DBL2NUM(RFLOAT_VALUE(nurat_to_f(self)) / RFLOAT_VALUE(other));
|
||
else if (RB_TYPE_P(other, T_RATIONAL)) {
|
||
if (f_zero_p(other))
|
||
rb_raise_zerodiv();
|
||
rb_num_zerodiv();
|
||
{
|
||
get_dat2(self, other);
|
||
... | ... | |
static VALUE
|
||
nurat_fdiv(VALUE self, VALUE other)
|
||
{
|
||
VALUE div;
|
||
if (f_zero_p(other))
|
||
return f_div(self, f_to_f(other));
|
||
return f_to_f(f_div(self, other));
|
||
return DBL2NUM(RFLOAT_VALUE(nurat_to_f(self)) / 0.0);
|
||
if (FIXNUM_P(other) && FIX2LONG(other) == 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_TYPE_P(div, T_FLOAT))
|
||
return div;
|
||
return rb_funcall(div, rb_intern("to_f"), 0);
|
||
}
|
||
inline static VALUE
|
||
... | ... | |
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();
|
||
if (FIX2INT(rb_int_cmp(ZERO, other)) == 1) {
|
||
rb_num_zerodiv();
|
||
}
|
||
else {
|
||
return f_rational_new_bang1(CLASS_OF(self), ZERO);
|
||
... | ... | |
get_dat1(self);
|
||
switch (FIX2INT(f_cmp(other, ZERO))) {
|
||
switch (FIX2INT(rb_int_cmp(other, ZERO))) {
|
||
case 1:
|
||
num = f_expt(dat->num, other);
|
||
den = f_expt(dat->den, other);
|
||
num = rb_int_pow(dat->num, other);
|
||
den = rb_int_pow(dat->den, other);
|
||
break;
|
||
case -1:
|
||
num = f_expt(dat->den, f_negate(other));
|
||
den = f_expt(dat->num, f_negate(other));
|
||
num = rb_int_pow(dat->den, rb_int_uminus(other));
|
||
den = rb_int_pow(dat->num, rb_int_uminus(other));
|
||
break;
|
||
default:
|
||
num = ONE;
|
||
... | ... | |
}
|
||
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);
|
||
return rb_float_pow(nurat_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);
|
||
return rb_float_pow(nurat_to_f(self), other);
|
||
}
|
||
else {
|
||
return rb_num_coerce_bin(self, other, id_expt);
|
||
return rb_num_coerce_bin(self, other, rb_intern("**"));
|
||
}
|
||
}
|
||
... | ... | |
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));
|
||
return rb_int_cmp(dat->num, other); /* c14n */
|
||
other = f_rational_new_bang1(CLASS_OF(self), other);
|
||
}
|
||
}
|
||
else if (RB_TYPE_P(other, T_FLOAT)) {
|
||
return f_cmp(f_to_f(self), other);
|
||
if (RB_TYPE_P(other, T_FLOAT)) {
|
||
return rb_dbl_cmp(RFLOAT_VALUE(nurat_to_f(self)), RFLOAT_VALUE(other));
|
||
}
|
||
else if (RB_TYPE_P(other, T_RATIONAL)) {
|
||
{
|
||
... | ... | |
num2 = f_imul(FIX2LONG(bdat->num), FIX2LONG(adat->den));
|
||
}
|
||
else {
|
||
num1 = f_mul(adat->num, bdat->den);
|
||
num2 = f_mul(bdat->num, adat->den);
|
||
num1 = rb_int_mul(adat->num, bdat->den);
|
||
num2 = rb_int_mul(bdat->num, adat->den);
|
||
}
|
||
return f_cmp(f_sub(num1, num2), ZERO);
|
||
return rb_int_cmp(rb_int_minus(num1, num2), ZERO);
|
||
}
|
||
}
|
||
else {
|
||
return rb_num_coerce_cmp(self, other, id_cmp);
|
||
return rb_num_coerce_cmp(self, other, rb_intern("<=>"));
|
||
}
|
||
}
|
||
... | ... | |
{
|
||
get_dat1(self);
|
||
if (f_zero_p(dat->num) && f_zero_p(other))
|
||
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;
|
||
if (f_eqeq_p(dat->num, other))
|
||
return Qtrue;
|
||
return Qfalse;
|
||
return rb_int_equal(dat->num, other);
|
||
}
|
||
}
|
||
else if (RB_TYPE_P(other, T_FLOAT)) {
|
||
return f_eqeq_p(f_to_f(self), other);
|
||
return f_boolcast(rb_dbl_cmp(RFLOAT_VALUE(nurat_to_f(self)), RFLOAT_VALUE(other))
|
||
== INT2FIX(0));
|
||
}
|
||
else if (RB_TYPE_P(other, T_RATIONAL)) {
|
||
{
|
||
get_dat2(self, other);
|
||
if (f_zero_p(adat->num) && f_zero_p(bdat->num))
|
||
if (INT_ZERO_P(adat->num) && INT_ZERO_P(bdat->num))
|
||
return Qtrue;
|
||
return f_boolcast(f_eqeq_p(adat->num, bdat->num) &&
|
||
f_eqeq_p(adat->den, bdat->den));
|
||
return f_boolcast(rb_int_equal(adat->num, bdat->num) &&
|
||
rb_int_equal(adat->den, bdat->den));
|
||
}
|
||
}
|
||
else {
|
||
... | ... | |
return rb_assoc_new(f_rational_new_bang1(CLASS_OF(self), other), self);
|
||
}
|
||
else if (RB_TYPE_P(other, T_FLOAT)) {
|
||
return rb_assoc_new(other, f_to_f(self));
|
||
return rb_assoc_new(other, nurat_to_f(self));
|
||
}
|
||
else if (RB_TYPE_P(other, T_RATIONAL)) {
|
||
return rb_assoc_new(other, self);
|
||
... | ... | |
}
|
||
#endif
|
||
/*
|
||
* call-seq:
|
||
* rat.positive? -> true or false
|
||
*
|
||
* 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));
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* rat.negative? -> true or false
|
||
*
|
||
* 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));
|
||
}
|
||
static VALUE
|
||
nurat_floor(VALUE self)
|
||
{
|
||
get_dat1(self);
|
||
return f_idiv(dat->num, dat->den);
|
||
return rb_int_idiv(dat->num, dat->den);
|
||
}
|
||
static VALUE
|
||
nurat_ceil(VALUE self)
|
||
{
|
||
get_dat1(self);
|
||
return f_negate(f_idiv(f_negate(dat->num), dat->den));
|
||
return rb_int_uminus(rb_int_idiv(rb_int_uminus(dat->num), dat->den));
|
||
}
|
||
/*
|
||
... | ... | |
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);
|
||
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);
|
||
}
|
||
static VALUE
|
||
... | ... | |
num = dat->num;
|
||
den = dat->den;
|
||
neg = f_negative_p(num);
|
||
neg = INT_NEGATIVE_P(num);
|
||
if (neg)
|
||
num = f_negate(num);
|
||
num = rb_int_uminus(num);
|
||
num = f_add(f_mul(num, TWO), den);
|
||
den = f_mul(den, TWO);
|
||
num = f_idiv(num, den);
|
||
num = rb_int_plus(rb_int_mul(num, TWO), den);
|
||
den = rb_int_mul(den, TWO);
|
||
num = rb_int_idiv(num, den);
|
||
if (neg)
|
||
num = f_negate(num);
|
||
num = rb_int_uminus(num);
|
||
return num;
|
||
}
|
||
... | ... | |
rb_raise(rb_eTypeError, "not an integer");
|
||
b = f_expt10(n);
|
||
s = f_mul(self, b);
|
||
s = nurat_mul(self, b);
|
||
if (k_float_p(s)) {
|
||
if (f_lt_p(n, ZERO))
|
||
if (INT_NEGATIVE_P(n))
|
||
return ZERO;
|
||
return self;
|
||
}
|
||
... | ... | |
s = (*func)(s);
|
||
s = f_div(f_rational_new_bang1(CLASS_OF(self), s), b);
|
||
s = nurat_div(f_rational_new_bang1(CLASS_OF(self), s), b);
|
||
if (f_lt_p(n, ONE))
|
||
s = f_to_i(s);
|
||
if (RB_TYPE_P(s, T_RATIONAL) && FIX2INT(rb_int_cmp(n, ONE)) < 0)
|
||
s = nurat_truncate(s);
|
||
return s;
|
||
}
|
||
... | ... | |
nurat_to_f(VALUE self)
|
||
{
|
||
get_dat1(self);
|
||
return f_fdiv(dat->num, dat->den);
|
||
return rb_int_fdiv(dat->num, dat->den);
|
||
}
|
||
/*
|
||
... | ... | |
if (argc == 0)
|
||
return self;
|
||
if (f_negative_p(self))
|
||
return f_negate(nurat_rationalize(argc, argv, f_abs(self)));
|
||
if (nurat_negative_p(self))
|
||
return nurat_negate(nurat_rationalize(argc, argv, nurat_negate(self)));
|
||
rb_scan_args(argc, argv, "01", &e);
|
||
e = f_abs(e);
|
||
... | ... | |
if (RARRAY_LEN(a) != 2)
|
||
rb_raise(rb_eArgError, "marshaled rational must have an array whose length is 2 but %ld", RARRAY_LEN(a));
|
||
if (f_zero_p(RARRAY_AREF(a, 1)))
|
||
rb_raise_zerodiv();
|
||
rb_num_zerodiv();
|
||
rb_ivar_set(self, id_i_num, RARRAY_AREF(a, 0));
|
||
rb_ivar_set(self, id_i_den, RARRAY_AREF(a, 1));
|
||
... | ... | |
return nurat_s_canonicalize_internal(rb_cRational, x, y);
|
||
}
|
||
static VALUE nurat_s_convert(int argc, VALUE *argv, VALUE klass);
|
||
VALUE
|
||
rb_Rational(VALUE x, VALUE y)
|
||
{
|
||
... | ... | |
numeric_quo(VALUE x, VALUE y)
|
||
{
|
||
if (RB_TYPE_P(y, T_FLOAT)) {
|
||
return f_fdiv(x, y);
|
||
return rb_funcall(x, rb_intern("fdiv"), 1, y);
|
||
}
|
||
#ifdef CANON
|
||
... | ... | |
{
|
||
x = rb_convert_type(x, T_RATIONAL, "Rational", "to_r");
|
||
}
|
||
return rb_funcall(x, '/', 1, y);
|
||
return nurat_div(x, y);
|
||
}
|
||
... | ... | |
return INT2FIX(1);
|
||
}
|
||
static VALUE float_to_r(VALUE self);
|
||
/*
|
||
* call-seq:
|
||
* flo.numerator -> integer
|
||
... | ... | |
double d = RFLOAT_VALUE(self);
|
||
if (isinf(d) || isnan(d))
|
||
return self;
|
||
return rb_call_super(0, 0);
|
||
return nurat_numerator(float_to_r(self));
|
||
}
|
||
/*
|
||
... | ... | |
double d = RFLOAT_VALUE(self);
|
||
if (isinf(d) || isnan(d))
|
||
return INT2FIX(1);
|
||
return rb_call_super(0, 0);
|
||
return nurat_denominator(float_to_r(self));
|
||
}
|
||
/*
|
||
... | ... | |
}
|
||
#endif
|
||
#define id_lshift rb_intern("<<")
|
||
#define f_lshift(x,n) rb_funcall((x), id_lshift, 1, (n))
|
||
/*
|
||
* call-seq:
|
||
* flt.to_r -> rational
|
||
... | ... | |
long ln = FIX2LONG(n);
|
||
if (ln == 0)
|
||
return f_to_r(f);
|
||
return rb_rational_new1(f);
|
||
if (ln > 0)
|
||
return f_to_r(f_lshift(f, n));
|
||
return rb_rational_new1(rb_int_lshift(f, n));
|
||
ln = -ln;
|
||
return rb_rational_new2(f, f_lshift(ONE, INT2FIX(ln)));
|
||
return rb_rational_new2(f, rb_int_lshift(ONE, INT2FIX(ln)));
|
||
}
|
||
#else
|
||
return f_to_r(f_mul(f, f_expt(INT2FIX(FLT_RADIX), n)));
|
||
f = rb_int_mul(f, rb_int_pow(INT2FIX(FLT_RADIX), n));
|
||
if (RB_TYPE_P(f, T_RATIONAL))
|
||
return f;
|
||
return rb_rational_new1(f);
|
||
#endif
|
||
}
|
||
... | ... | |
b = f_add(flt, e);
|
||
if (f_eqeq_p(a, b))
|
||
return f_to_r(flt);
|
||
return float_to_r(flt);
|
||
nurat_rationalize_internal(a, b, &p, &q);
|
||
return rb_rational_new2(p, q);
|
||
... | ... | |
VALUE a, b, f, n, p, q;
|
||
float_decode_internal(flt, &f, &n);
|
||
if (f_zero_p(f) || f_positive_p(n))
|
||
return rb_rational_new1(f_lshift(f, n));
|
||
if (INT_ZERO_P(f) || FIX2INT(n) >= 0)
|
||
return rb_rational_new1(rb_int_lshift(f, n));
|
||
#if FLT_RADIX == 2
|
||
{
|
||
VALUE two_times_f, den;
|
||
two_times_f = f_mul(TWO, f);
|
||
den = f_lshift(ONE, f_sub(ONE, n));
|
||
two_times_f = rb_int_mul(TWO, f);
|
||
den = rb_int_lshift(ONE, rb_int_minus(ONE, n));
|
||
a = rb_rational_new2(f_sub(two_times_f, ONE), den);
|
||
b = rb_rational_new2(f_add(two_times_f, ONE), den);
|
||
a = rb_rational_new2(rb_int_minus(two_times_f, ONE), den);
|
||
b = rb_rational_new2(rb_int_plus(two_times_f, ONE), den);
|
||
}
|
||
#else
|
||
{
|
||
VALUE radix_times_f, den;
|
||
radix_times_f = f_mul(INT2FIX(FLT_RADIX), f);
|
||
den = f_expt(INT2FIX(FLT_RADIX), f_sub(ONE, n));
|
||
radix_times_f = rb_int_mul(INT2FIX(FLT_RADIX), f);
|
||
den = rb_int_pow(INT2FIX(FLT_RADIX), rb_int_minus(ONE, n));
|
||
a = rb_rational_new2(f_sub(radix_times_f, INT2FIX(FLT_RADIX - 1)), den);
|
||
b = rb_rational_new2(f_add(radix_times_f, INT2FIX(FLT_RADIX - 1)), den);
|
||
a = rb_rational_new2(rb_int_minus(radix_times_f, INT2FIX(FLT_RADIX - 1)), den);
|
||
b = rb_rational_new2(rb_int_plus(radix_times_f, INT2FIX(FLT_RADIX - 1)), den);
|
||
}
|
||
#endif
|
||
if (f_eqeq_p(a, b))
|
||
return f_to_r(flt);
|
||
if (nurat_eqeq_p(a, b))
|
||
return float_to_r(flt);
|
||
nurat_rationalize_internal(a, b, &p, &q);
|
||
return rb_rational_new2(p, q);
|
||
... | ... | |
float_rationalize(int argc, VALUE *argv, VALUE self)
|
||
{
|
||
VALUE e;
|
||
double d = RFLOAT_VALUE(self);
|
||
if (f_negative_p(self))
|
||
return f_negate(float_rationalize(argc, argv, f_abs(self)));
|
||
if (d < 0.0)
|
||
return nurat_negate(float_rationalize(argc, argv, DBL2NUM(-d)));
|
||
rb_scan_args(argc, argv, "01", &e);
|
||
... | ... | |
return 0;
|
||
{
|
||
VALUE l = f_expt10(INT2NUM(count));
|
||
*num = f_mul(*num, l);
|
||
*num = f_add(*num, fp);
|
||
*num = f_div(*num, l);
|
||
#ifdef CANON
|
||
if (canonicalization) {
|
||
*num = rb_int_mul(*num, l);
|
||
*num = rb_int_plus(*num, fp);
|
||
*num = rb_rational_new2(*num, l);
|
||
}
|
||
else
|
||
#endif
|
||
{
|
||
*num = nurat_mul(*num, l);
|
||
*num = rb_rational_plus(*num, fp);
|
||
*num = nurat_div(*num, l);
|
||
}
|
||
}
|
||
}
|
||
... | ... | |
if (!read_digits(s, strict, &exp, NULL))
|
||
return 0;
|
||
if (expsign == '-')
|
||
exp = f_negate(exp);
|
||
exp = rb_int_uminus(exp);
|
||
}
|
||
if (numsign == '-')
|
||
*num = f_negate(*num);
|
||
*num = nurat_negate(*num);
|
||
if (!NIL_P(exp)) {
|
||
VALUE l = f_expt10(exp);
|
||
*num = f_mul(*num, l);
|
||
*num = nurat_mul(*num, l);
|
||
}
|
||
return 1;
|
||
}
|
||
... | ... | |
if (!read_den(s, strict, &den))
|
||
return 0;
|
||
if (!(FIXNUM_P(den) && FIX2LONG(den) == 1))
|
||
*num = f_div(*num, den);
|
||
*num = nurat_div(*num, den);
|
||
}
|
||
return 1;
|
||
}
|
||
... | ... | |
rb_match_busy(backref);
|
||
if (RB_TYPE_P(a1, T_FLOAT)) {
|
||
a1 = f_to_r(a1);
|
||
a1 = float_to_r(a1);
|
||
}
|
||
else if (RB_TYPE_P(a1, T_STRING)) {
|
||
a1 = string_to_r_strict(a1);
|
||
}
|
||
if (RB_TYPE_P(a2, T_FLOAT)) {
|
||
a2 = f_to_r(a2);
|
||
a2 = float_to_r(a2);
|
||
}
|
||
else if (RB_TYPE_P(a2, T_STRING)) {
|
||
a2 = string_to_r_strict(a2);
|
||
... | ... | |
assert(fprintf(stderr, "assert() is now active\n"));
|
||
id_abs = rb_intern("abs");
|
||
id_cmp = rb_intern("<=>");
|
||
id_convert = rb_intern("convert");
|
||
id_eqeq_p = rb_intern("==");
|
||
id_expt = rb_intern("**");
|
||
id_fdiv = rb_intern("fdiv");
|
||
id_idiv = rb_intern("div");
|
||
id_integer_p = rb_intern("integer?");
|
||
id_negate = rb_intern("-@");
|
||
id_to_f = rb_intern("to_f");
|
||
id_to_i = rb_intern("to_i");
|
||
id_truncate = rb_intern("truncate");
|
||
id_i_num = rb_intern("@numerator");
|
||
id_i_den = rb_intern("@denominator");
|
||
... | ... | |
rb_define_method(rb_cRational, "numerator", nurat_numerator, 0);
|
||
rb_define_method(rb_cRational, "denominator", nurat_denominator, 0);
|
||
rb_define_method(rb_cRational, "-@", nurat_negate, 0);
|
||
rb_define_method(rb_cRational, "+", rb_rational_plus, 1);
|
||
rb_define_method(rb_cRational, "-", nurat_sub, 1);
|
||
rb_define_method(rb_cRational, "*", nurat_mul, 1);
|
||
... | ... | |
rb_define_method(rb_cRational, "rational?", nurat_true, 0);
|
||
rb_define_method(rb_cRational, "exact?", nurat_true, 0);
|
||
#endif
|
||
rb_define_method(rb_cRational, "positive?", nurat_positive_p, 0);
|
||
rb_define_method(rb_cRational, "negative?", nurat_negative_p, 0);
|
||
rb_define_method(rb_cRational, "floor", nurat_floor_n, -1);
|
||
rb_define_method(rb_cRational, "ceil", nurat_ceil_n, -1);
|