summaryrefslogtreecommitdiff
path: root/rational.c
diff options
context:
space:
mode:
Diffstat (limited to 'rational.c')
-rw-r--r--rational.c92
1 files changed, 48 insertions, 44 deletions
diff --git a/rational.c b/rational.c
index 7274ace1ff..3b352ea9da 100644
--- a/rational.c
+++ b/rational.c
@@ -27,8 +27,8 @@
VALUE rb_cRational;
static ID id_Unify, id_abs, id_cmp, id_convert, id_equal_p, id_expt,
- id_floor, id_format, id_idiv, id_inspect, id_integer_p, id_negate,
- id_new, id_new_bang, id_to_f, id_to_i, id_to_s, id_truncate;
+ id_floor, id_format, id_hash, id_idiv, id_inspect, id_integer_p,
+ id_negate, id_to_f, id_to_i, id_to_s, id_truncate;
#define f_boolcast(x) ((x) ? Qtrue : Qfalse)
@@ -139,6 +139,7 @@ binop(xor, '^')
fun1(abs)
fun1(floor)
+fun1(hash)
fun1(inspect)
fun1(integer_p)
fun1(negate)
@@ -166,6 +167,8 @@ f_negative_p(VALUE x)
return rb_funcall(x, '<', 1, ZERO);
}
+#define f_positive_p(x) (!f_negative_p(x))
+
inline static VALUE
f_zero_p(VALUE x)
{
@@ -174,6 +177,8 @@ f_zero_p(VALUE x)
return rb_funcall(x, id_equal_p, 1, ZERO);
}
+#define f_nonzero_p(x) (!f_zero_p(x))
+
inline static VALUE
f_one_p(VALUE x)
{
@@ -212,6 +217,9 @@ k_rational_p(VALUE x)
return f_kind_of_p(x, rb_cRational);
}
+#define k_exact_p(x) (!k_float_p(x))
+#define k_inexact_p(x) k_float_p(x)
+
#ifndef NDEBUG
#define f_gcd f_gcd_orig
#endif
@@ -276,7 +284,7 @@ inline static VALUE
f_gcd(VALUE x, VALUE y)
{
VALUE r = f_gcd_orig(x, y);
- if (!f_zero_p(r)) {
+ if (f_nonzero_p(r)) {
assert(f_zero_p(f_mod(x, r)));
assert(f_zero_p(f_mod(y, r)));
}
@@ -362,8 +370,8 @@ f_rational_new_bang1(VALUE klass, VALUE x)
inline static VALUE
f_rational_new_bang2(VALUE klass, VALUE x, VALUE y)
{
- assert(!f_negative_p(y));
- assert(!f_zero_p(y));
+ assert(f_positive_p(y));
+ assert(f_nonzero_p(y));
return nurat_s_new_internal(klass, x, y);
}
@@ -772,7 +780,7 @@ nurat_fdiv(VALUE self, VALUE other)
static VALUE
nurat_expt(VALUE self, VALUE other)
{
- if (f_zero_p(other))
+ if (k_exact_p(other) && f_zero_p(other))
return f_rational_new_bang1(CLASS_OF(self), ONE);
if (k_rational_p(other)) {
@@ -951,7 +959,7 @@ nurat_quotrem(VALUE self, VALUE other)
static VALUE
nurat_abs(VALUE self)
{
- if (!f_negative_p(self))
+ if (f_positive_p(self))
return self;
return f_negate(self);
}
@@ -1102,7 +1110,7 @@ static VALUE
nurat_hash(VALUE self)
{
get_dat1(self);
- return f_xor(dat->num, dat->den);
+ return f_xor(f_hash(dat->num), f_hash(dat->den));
}
static VALUE
@@ -1124,8 +1132,12 @@ nurat_inspect(VALUE self)
static VALUE
nurat_marshal_dump(VALUE self)
{
+ VALUE a;
get_dat1(self);
- return rb_assoc_new(dat->num, dat->den);
+
+ a = rb_assoc_new(dat->num, dat->den);
+ rb_copy_generic_ivar(a, self);
+ return a;
}
static VALUE
@@ -1134,6 +1146,7 @@ nurat_marshal_load(VALUE self, VALUE a)
get_dat1(self);
dat->num = RARRAY_PTR(a)[0];
dat->den = RARRAY_PTR(a)[1];
+ rb_copy_generic_ivar(self, a);
if (f_zero_p(dat->den))
rb_raise_zerodiv();
@@ -1251,20 +1264,20 @@ make_patterns(void)
if (rat_pat) return;
rat_pat = rb_reg_new(rat_pat_source, sizeof rat_pat_source - 1, 0);
- rb_global_variable(&rat_pat);
+ rb_gc_register_mark_object(rat_pat);
an_e_pat = rb_reg_new(an_e_pat_source, sizeof an_e_pat_source - 1, 0);
- rb_global_variable(&an_e_pat);
+ rb_gc_register_mark_object(an_e_pat);
a_dot_pat = rb_reg_new(a_dot_pat_source, sizeof a_dot_pat_source - 1, 0);
- rb_global_variable(&a_dot_pat);
+ rb_gc_register_mark_object(a_dot_pat);
underscores_pat = rb_reg_new(underscores_pat_source,
sizeof underscores_pat_source - 1, 0);
- rb_global_variable(&underscores_pat);
+ rb_gc_register_mark_object(underscores_pat);
an_underscore = rb_str_new2("_");
- rb_global_variable(&an_underscore);
+ rb_gc_register_mark_object(an_underscore);
}
#define id_match rb_intern("match")
@@ -1393,26 +1406,18 @@ nurat_s_convert(int argc, VALUE *argv, VALUE klass)
{
VALUE a1, a2, backref;
- rb_scan_args(argc, argv, "02", &a1, &a2);
+ rb_scan_args(argc, argv, "11", &a1, &a2);
switch (TYPE(a1)) {
case T_COMPLEX:
- if (k_float_p(RCOMPLEX(a1)->image) || !f_zero_p(RCOMPLEX(a1)->image)) {
- VALUE s = f_to_s(a1);
- rb_raise(rb_eRangeError, "can't accept %s",
- StringValuePtr(s));
- }
- a1 = RCOMPLEX(a1)->real;
+ if (k_exact_p(RCOMPLEX(a1)->imag) && f_zero_p(RCOMPLEX(a1)->imag))
+ a1 = RCOMPLEX(a1)->real;
}
switch (TYPE(a2)) {
case T_COMPLEX:
- if (k_float_p(RCOMPLEX(a2)->image) || !f_zero_p(RCOMPLEX(a2)->image)) {
- VALUE s = f_to_s(a2);
- rb_raise(rb_eRangeError, "can't accept %s",
- StringValuePtr(s));
- }
- a2 = RCOMPLEX(a2)->real;
+ if (k_exact_p(RCOMPLEX(a2)->imag) && f_zero_p(RCOMPLEX(a2)->imag))
+ a2 = RCOMPLEX(a2)->real;
}
backref = rb_backref_get();
@@ -1446,14 +1451,18 @@ nurat_s_convert(int argc, VALUE *argv, VALUE klass)
switch (TYPE(a1)) {
case T_RATIONAL:
- if (NIL_P(a2) || f_zero_p(a2))
+ if (argc == 1 || (k_exact_p(a2) && f_one_p(a2)))
return a1;
- return f_div(a1, a2);
}
- switch (TYPE(a2)) {
- case T_RATIONAL:
- return f_div(a1, a2);
+ if (argc == 1) {
+ if (k_numeric_p(a1) && !f_integer_p(a1))
+ return a1;
+ }
+ else {
+ if ((k_numeric_p(a1) && k_numeric_p(a2)) &&
+ (!f_integer_p(a1) || !f_integer_p(a2)))
+ return f_div(a1, a2);
}
{
@@ -1464,12 +1473,6 @@ nurat_s_convert(int argc, VALUE *argv, VALUE klass)
}
}
-static VALUE
-nurat_s_induced_from(VALUE klass, VALUE n)
-{
- return f_to_r(n);
-}
-
void
Init_Rational(void)
{
@@ -1486,12 +1489,11 @@ Init_Rational(void)
id_expt = rb_intern("**");
id_floor = rb_intern("floor");
id_format = rb_intern("format");
+ id_hash = rb_intern("hash");
id_idiv = rb_intern("div");
id_inspect = rb_intern("inspect");
id_integer_p = rb_intern("integer?");
id_negate = rb_intern("-@");
- id_new = rb_intern("new");
- id_new_bang = rb_intern("new!");
id_to_f = rb_intern("to_f");
id_to_i = rb_intern("to_i");
id_to_s = rb_intern("to_s");
@@ -1587,8 +1589,10 @@ Init_Rational(void)
rb_define_singleton_method(rb_cRational, "convert", nurat_s_convert, -1);
rb_funcall(rb_cRational, rb_intern("private_class_method"), 1,
ID2SYM(rb_intern("convert")));
-
- rb_include_module(rb_cRational, rb_mPrecision);
- rb_define_singleton_method(rb_cRational, "induced_from",
- nurat_s_induced_from, 1);
}
+
+/*
+Local variables:
+c-file-style: "ruby"
+End:
+*/