summaryrefslogtreecommitdiff
path: root/rational.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-12-29 10:32:48 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-12-29 10:32:48 +0000
commite383c2ea4616fb38f3b571b74d5fea8178da8705 (patch)
tree67a086531672e2e89a4d982cd438d115e1369218 /rational.c
parentff93ad62bd6cb00365c5b4cabf5be07b6eb37b69 (diff)
rational.c: refactor to_r
* rational.c (read_num, read_rat_nos): refactor to curtail creating Rational objects. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57233 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'rational.c')
-rw-r--r--rational.c123
1 files changed, 57 insertions, 66 deletions
diff --git a/rational.c b/rational.c
index 1bbea4fc72..439f9673da 100644
--- a/rational.c
+++ b/rational.c
@@ -481,15 +481,19 @@ nurat_canonicalize(VALUE *num, VALUE *den)
}
}
+static void
+nurat_reduce(VALUE *x, VALUE *y)
+{
+ VALUE gcd = f_gcd(*x, *y);
+ *x = f_idiv(*x, gcd);
+ *y = f_idiv(*y, gcd);
+}
+
inline static VALUE
nurat_s_canonicalize_internal(VALUE klass, VALUE num, VALUE den)
{
- VALUE gcd;
-
nurat_canonicalize(&num, &den);
- gcd = f_gcd(num, den);
- num = f_idiv(num, gcd);
- den = f_idiv(den, gcd);
+ nurat_reduce(&num, &den);
if (canonicalization && f_one_p(den))
return num;
@@ -2311,18 +2315,16 @@ islettere(int c)
}
static int
-read_num(const char **s, int numsign, int strict,
- VALUE *num)
+read_num(const char **s, int strict, VALUE *num, VALUE *div)
{
- VALUE ip, fp, exp;
-
- *num = rb_rational_new2(ZERO, ONE);
- exp = Qnil;
+ VALUE fp = ONE, exp, fn = ZERO;
+ int expsign = 0;
+ *div = ONE;
+ *num = ZERO;
if (**s != '.') {
- if (!read_digits(s, strict, &ip, NULL))
+ if (!read_digits(s, strict, num, NULL))
return 0;
- *num = rb_rational_new2(ip, ONE);
}
if (**s == '.') {
@@ -2333,81 +2335,70 @@ read_num(const char **s, int numsign, int strict,
return 0;
{
VALUE l = f_expt10(INT2NUM(count));
- if (canonicalization) {
- *num = rb_int_mul(*num, l);
- *num = rb_int_plus(*num, fp);
- *num = rb_rational_new2(*num, l);
- }
- else
- {
- *num = nurat_mul(*num, l);
- *num = rb_rational_plus(*num, fp);
- *num = nurat_div(*num, l);
- }
+ *num = *num == ZERO ? fp : rb_int_plus(rb_int_mul(*num, l), fp);
+ *div = l;
+ fn = INT2NUM(count);
}
}
if (islettere(**s)) {
- int expsign;
-
(*s)++;
expsign = read_sign(s);
if (!read_digits(s, strict, &exp, NULL))
return 0;
- if (expsign == '-')
- exp = rb_int_uminus(exp);
- }
-
- if (numsign == '-') {
- if (RB_TYPE_P(*num, T_RATIONAL)) {
- *num = rb_rational_uminus(*num);
- }
- else {
- *num = rb_int_uminus(*num);
- }
- }
- if (!NIL_P(exp)) {
- VALUE l = f_expt10(exp);
- if (RB_TYPE_P(*num, T_RATIONAL)) {
- *num = nurat_mul(*num, l);
- }
- else {
- *num = rb_int_mul(*num, l);
+ if (exp != ZERO) {
+ if (expsign == '-') {
+ if (fn != ZERO) exp = rb_int_plus(exp, fn);
+ *div = f_expt10(exp);
+ }
+ else {
+ if (fn != ZERO) exp = rb_int_minus(exp, fn);
+ if (INT_NEGATIVE_P(exp)) {
+ *div = f_expt10(exp);
+ }
+ else {
+ *num = rb_int_mul(*num, f_expt10(exp));
+ *div = ONE;
+ }
+ }
}
}
- return 1;
-}
-inline static int
-read_den(const char **s, int strict,
- VALUE *num)
-{
- if (!read_digits(s, strict, num, NULL))
- return 0;
return 1;
}
static int
-read_rat_nos(const char **s, int sign, int strict,
- VALUE *num)
+read_rat_nos(const char **s, int sign, int strict, VALUE *num)
{
- VALUE den;
+ VALUE den = ONE, div;
- if (!read_num(s, sign, strict, num))
+ if (!read_num(s, strict, num, &div)) {
+ failed:
+ if (!canonicalization && !strict)
+ *num = rb_rational_raw(*num, div);
return 0;
+ }
+ if (div != ONE) nurat_reduce(num, &div);
+ den = div;
if (**s == '/') {
(*s)++;
- if (!read_den(s, strict, &den))
- return 0;
- if (!(FIXNUM_P(den) && FIX2LONG(den) == 1)) {
- if (RB_TYPE_P(*num, T_RATIONAL)) {
- *num = nurat_div(*num, den);
- }
- else {
- *num = rb_int_div(*num, den);
- }
+ if (!read_digits(s, strict, &den, NULL)) goto failed;
+ nurat_reduce(num, &den);
+ if (div != ONE && den != ONE)
+ den = rb_int_mul(den, div);
+ }
+
+ if (sign == '-') {
+ if (FIXNUM_P(*num)) {
+ *num = rb_int_uminus(*num);
+ }
+ else {
+ BIGNUM_NEGATE(*num);
+ *num = rb_big_norm(*num);
}
}
+ if (!canonicalization || den != ONE)
+ *num = rb_rational_raw(*num, den);
return 1;
}