[macruby-changes] [2117] MacRuby/branches/experimental

source_changes at macosforge.org source_changes at macosforge.org
Wed Jul 29 22:04:55 PDT 2009


Revision: 2117
          http://trac.macosforge.org/projects/ruby/changeset/2117
Author:   lsansonetti at apple.com
Date:     2009-07-29 22:04:52 -0700 (Wed, 29 Jul 2009)
Log Message:
-----------
ported Rational and Complex to the new runtime APIs, patch by Dan Sinclair

Modified Paths:
--------------
    MacRuby/branches/experimental/complex.c
    MacRuby/branches/experimental/include/ruby/ruby.h
    MacRuby/branches/experimental/numeric.c
    MacRuby/branches/experimental/rational.c

Modified: MacRuby/branches/experimental/complex.c
===================================================================
--- MacRuby/branches/experimental/complex.c	2009-07-29 19:32:58 UTC (rev 2116)
+++ MacRuby/branches/experimental/complex.c	2009-07-30 05:04:52 UTC (rev 2117)
@@ -1,5 +1,5 @@
 /*
-  complex.c: Coded by Tadayoshi Funaba 2008
+  complex.c: Coded by Tadayoshi Funaba 2008,2009
 
   This implementation is based on Keiju Ishitsuka's Complex library
   which is written in ruby.
@@ -7,26 +7,21 @@
 
 #include "ruby.h"
 #include <math.h>
+#include "ruby/re.h"
 
 #define NDEBUG
 #include <assert.h>
 
-#ifndef COMPLEX_NAME
-#define COMPLEX_NAME "Complex"
-#endif
-
 #define ZERO INT2FIX(0)
 #define ONE INT2FIX(1)
 #define TWO INT2FIX(2)
 
 VALUE rb_cComplex;
 
-static ID id_Unify, id_abs, id_abs2, id_arg, id_atan2_bang, id_cmp,
-  id_conjugate, id_convert, id_cos, id_denominator, id_divmod,
-  id_equal_p, id_exact_p, id_exp_bang, id_expt, id_floor, id_format,
-  id_hypot, id_idiv, id_inspect, id_log_bang, id_negate, id_new, id_new_bang,
-  id_numerator, id_polar, id_quo, id_scalar_p, id_sin, id_sqrt, id_to_f,
-  id_to_i, id_to_r, id_to_s, id_truncate;
+static ID id_abs, id_abs2, id_arg, id_cmp, id_conj, id_convert,
+    id_denominator, id_divmod, id_eqeq_p, id_expt, id_fdiv,  id_floor,
+    id_idiv, id_imag, id_inspect, id_negate, id_numerator, id_quo,
+    id_real, id_real_p, id_to_f, id_to_i, id_to_r, id_to_s;
 
 #define f_boolcast(x) ((x) ? Qtrue : Qfalse)
 
@@ -65,75 +60,56 @@
     return rb_funcall(rb_mMath, id_##n, 2, x, y);\
 }
 
+#define PRESERVE_SIGNEDZERO
+
 inline static VALUE
 f_add(VALUE x, VALUE y)
 {
-    VALUE r;
-    if (FIXNUM_P(y)) {
-	if (FIX2LONG(y) == 0)
-	    r = x;
-	else
-	    r = rb_funcall(x, '+', 1, y);
-    }
-    else if (FIXNUM_P(x)) {
-	if (FIX2LONG(x) == 0)
-	    r = y;
-	else
-	    r = rb_funcall(x, '+', 1, y);
-    }
-    else
-	r = rb_funcall(x, '+', 1, y);
-    return r;
+#ifndef PRESERVE_SIGNEDZERO
+    if (FIXNUM_P(y) && FIX2LONG(y) == 0)
+	return x;
+    else if (FIXNUM_P(x) && FIX2LONG(x) == 0)
+	return y;
+#endif
+    return rb_funcall(x, '+', 1, y);
 }
 
 inline static VALUE
 f_cmp(VALUE x, VALUE y)
 {
-    VALUE r;
     if (FIXNUM_P(x) && FIXNUM_P(y)) {
 	long c = FIX2LONG(x) - FIX2LONG(y);
 	if (c > 0)
 	    c = 1;
 	else if (c < 0)
 	    c = -1;
-	r = INT2FIX(c);
+	return INT2FIX(c);
     }
-    else
-	r = rb_funcall(x, id_cmp, 1, y);
-    return r;
+    return rb_funcall(x, id_cmp, 1, y);
 }
 
 inline static VALUE
 f_div(VALUE x, VALUE y)
 {
-    VALUE r;
     if (FIXNUM_P(y) && FIX2LONG(y) == 1)
-	r = x;
-    else
-	r = rb_funcall(x, '/', 1, y);
-    return r;
+	return x;
+    return rb_funcall(x, '/', 1, y);
 }
 
 inline static VALUE
 f_gt_p(VALUE x, VALUE y)
 {
-    VALUE r;
     if (FIXNUM_P(x) && FIXNUM_P(y))
-	r = f_boolcast(FIX2LONG(x) > FIX2LONG(y));
-    else
-	r = rb_funcall(x, '>', 1, y);
-    return r;
+	return f_boolcast(FIX2LONG(x) > FIX2LONG(y));
+    return rb_funcall(x, '>', 1, y);
 }
 
 inline static VALUE
 f_lt_p(VALUE x, VALUE y)
 {
-    VALUE r;
     if (FIXNUM_P(x) && FIXNUM_P(y))
-	r = f_boolcast(FIX2LONG(x) < FIX2LONG(y));
-    else
-	r = rb_funcall(x, '<', 1, y);
-    return r;
+	return f_boolcast(FIX2LONG(x) < FIX2LONG(y));
+    return rb_funcall(x, '<', 1, y);
 }
 
 binop(mod, '%')
@@ -141,121 +117,120 @@
 inline static VALUE
 f_mul(VALUE x, VALUE y)
 {
-    VALUE r;
+#ifndef PRESERVE_SIGNEDZERO
     if (FIXNUM_P(y)) {
-	long _iy = FIX2LONG(y);
-	if (_iy == 0) {
-	    if (TYPE(x) == T_FLOAT)
-		r = rb_float_new(0.0);
-	    else
-		r = ZERO;
+	long iy = FIX2LONG(y);
+	if (iy == 0) {
+	    if (FIXNUM_P(x) || TYPE(x) == T_BIGNUM)
+		return ZERO;
 	}
-	else if (_iy == 1)
-	    r = x;
-	else
-	    r = rb_funcall(x, '*', 1, y);
+	else if (iy == 1)
+	    return x;
     }
     else if (FIXNUM_P(x)) {
-	long _ix = FIX2LONG(x);
-	if (_ix == 0) {
-	    if (TYPE(y) == T_FLOAT)
-		r = rb_float_new(0.0);
-	    else
-		r = ZERO;
+	long ix = FIX2LONG(x);
+	if (ix == 0) {
+	    if (FIXNUM_P(y) || TYPE(y) == T_BIGNUM)
+		return ZERO;
 	}
-	else if (_ix == 1)
-	    r = y;
-	else
-	    r = rb_funcall(x, '*', 1, y);
+	else if (ix == 1)
+	    return y;
     }
-    else
-	r = rb_funcall(x, '*', 1, y);
-    return r;
+#endif
+    return rb_funcall(x, '*', 1, y);
 }
 
 inline static VALUE
 f_sub(VALUE x, VALUE y)
 {
-    VALUE r;
-    if (FIXNUM_P(y)) {
-	if (FIX2LONG(y) == 0)
-	    r = x;
-	else
-	    r = rb_funcall(x, '-', 1, y);
-    }
-    else
-	r = rb_funcall(x, '-', 1, y);
-    return r;
+#ifndef PRESERVE_SIGNEDZERO
+    if (FIXNUM_P(y) && FIX2LONG(y) == 0)
+	return x;
+#endif
+    return rb_funcall(x, '-', 1, y);
 }
 
-binop(xor, '^')
-
 fun1(abs)
 fun1(abs2)
 fun1(arg)
-fun1(conjugate)
+fun1(conj)
 fun1(denominator)
-fun1(exact_p)
 fun1(floor)
+fun1(imag)
 fun1(inspect)
 fun1(negate)
 fun1(numerator)
-fun1(polar)
-fun1(scalar_p)
+fun1(real)
+fun1(real_p)
+
 fun1(to_f)
 fun1(to_i)
 fun1(to_r)
 fun1(to_s)
-fun1(truncate)
 
 fun2(divmod)
 
 inline static VALUE
-f_equal_p(VALUE x, VALUE y)
+f_eqeq_p(VALUE x, VALUE y)
 {
-    VALUE r;
     if (FIXNUM_P(x) && FIXNUM_P(y))
-	r = f_boolcast(FIX2LONG(x) == FIX2LONG(y));
-    else
-	r = rb_funcall(x, id_equal_p, 1, y);
-    return r;
+	return f_boolcast(FIX2LONG(x) == FIX2LONG(y));
+    return rb_funcall(x, id_eqeq_p, 1, y);
 }
 
 fun2(expt)
+fun2(fdiv)
 fun2(idiv)
 fun2(quo)
 
 inline static VALUE
 f_negative_p(VALUE x)
 {
-    VALUE r;
     if (FIXNUM_P(x))
-	r = f_boolcast(FIX2LONG(x) < 0);
-    else
-	r = rb_funcall(x, '<', 1, ZERO);
-    return r;
+	return f_boolcast(FIX2LONG(x) < 0);
+    return rb_funcall(x, '<', 1, ZERO);
 }
 
+#define f_positive_p(x) (!f_negative_p(x))
+
 inline static VALUE
 f_zero_p(VALUE x)
 {
-    VALUE r;
-    if (FIXNUM_P(x))
-	r = f_boolcast(FIX2LONG(x) == 0);
-    else
-	r = rb_funcall(x, id_equal_p, 1, ZERO);
-    return r;
+    switch (TYPE(x)) {
+      case T_FIXNUM:
+	return f_boolcast(FIX2LONG(x) == 0);
+      case T_BIGNUM:
+	return Qfalse;
+      case T_RATIONAL:
+      {
+	  VALUE num = RRATIONAL(x)->num;
+
+	  return f_boolcast(FIXNUM_P(num) && FIX2LONG(num) == 0);
+      }
+    }
+    return rb_funcall(x, id_eqeq_p, 1, ZERO);
 }
 
+#define f_nonzero_p(x) (!f_zero_p(x))
+
 inline static VALUE
 f_one_p(VALUE x)
 {
-    VALUE r;
-    if (FIXNUM_P(x))
-	r = f_boolcast(FIX2LONG(x) == 1);
-    else
-	r = rb_funcall(x, id_equal_p, 1, ONE);
-    return r;
+    switch (TYPE(x)) {
+      case T_FIXNUM:
+	return f_boolcast(FIX2LONG(x) == 1);
+      case T_BIGNUM:
+	return Qfalse;
+      case T_RATIONAL:
+      {
+	  VALUE num = RRATIONAL(x)->num;
+	  VALUE den = RRATIONAL(x)->den;
+
+	  return f_boolcast(FIXNUM_P(num) && FIX2LONG(num) == 1 &&
+			    FIXNUM_P(den) && FIX2LONG(den) == 1);
+      }
+    }
+    return rb_funcall(x, id_eqeq_p, 1, ONE);
 }
 
 inline static VALUE
@@ -277,6 +252,18 @@
 }
 
 inline static VALUE
+k_fixnum_p(VALUE x)
+{
+    return f_kind_of_p(x, rb_cFixnum);
+}
+
+inline static VALUE
+k_bignum_p(VALUE x)
+{
+    return f_kind_of_p(x, rb_cBignum);
+}
+
+inline static VALUE
 k_float_p(VALUE x)
 {
     return f_kind_of_p(x, rb_cFloat);
@@ -294,25 +281,11 @@
     return f_kind_of_p(x, rb_cComplex);
 }
 
-inline static VALUE
-f_generic_p(VALUE x)
-{
-    switch (TYPE(x)) {
-      case T_FIXNUM:
-      case T_BIGNUM:
-      case T_FLOAT:
-      case T_RATIONAL:
-	return Qtrue;
-      default:
-	return Qfalse;
-    }
-}
+#define k_exact_p(x) (!k_float_p(x))
+#define k_inexact_p(x) k_float_p(x)
 
-static VALUE
-nucomp_s_generic_p(VALUE klass, VALUE x)
-{
-    return f_generic_p(x);
-}
+#define k_exact_zero_p(x) (k_exact_p(x) && f_zero_p(x))
+#define k_exact_one_p(x) (k_exact_p(x) && f_one_p(x))
 
 #define get_dat1(x) \
     struct RComplex *dat;\
@@ -324,59 +297,76 @@
     bdat = ((struct RComplex *)(y))
 
 inline static VALUE
-nucomp_s_new_internal(VALUE klass, VALUE real, VALUE image)
+nucomp_s_new_internal(VALUE klass, VALUE real, VALUE imag)
 {
     NEWOBJ(obj, struct RComplex);
     OBJSETUP(obj, klass, T_COMPLEX);
 
     obj->real = real;
-    obj->image = image;
+    obj->imag = imag;
 
     return (VALUE)obj;
 }
 
 static VALUE
-nucomp_s_alloc(VALUE klass)
+nucomp_s_alloc(VALUE klass, SEL sel)
 {
     return nucomp_s_new_internal(klass, ZERO, ZERO);
 }
 
+#if 0
 static VALUE
 nucomp_s_new_bang(int argc, VALUE *argv, VALUE klass)
 {
-    VALUE real, image;
+    VALUE real, imag;
 
-    switch (rb_scan_args(argc, argv, "11", &real, &image)) {
+    switch (rb_scan_args(argc, argv, "11", &real, &imag)) {
       case 1:
 	if (!k_numeric_p(real))
 	    real = f_to_i(real);
-	image = ZERO;
+	imag = ZERO;
 	break;
       default:
 	if (!k_numeric_p(real))
 	    real = f_to_i(real);
-	if (!k_numeric_p(image))
-	    image = f_to_i(image);
+	if (!k_numeric_p(imag))
+	    imag = f_to_i(imag);
 	break;
     }
 
-    return nucomp_s_new_internal(klass, real, image);
+    return nucomp_s_new_internal(klass, real, imag);
 }
+#endif
 
 inline static VALUE
 f_complex_new_bang1(VALUE klass, VALUE x)
 {
+    assert(!k_complex_p(x));
     return nucomp_s_new_internal(klass, x, ZERO);
 }
 
 inline static VALUE
 f_complex_new_bang2(VALUE klass, VALUE x, VALUE y)
 {
+    assert(!k_complex_p(x));
+    assert(!k_complex_p(y));
     return nucomp_s_new_internal(klass, x, y);
 }
 
-#define f_unify_p(klass) rb_const_defined(klass, id_Unify)
+#ifdef CANONICALIZATION_FOR_MATHN
+#define CANON
+#endif
 
+#ifdef CANON
+static int canonicalization = 0;
+
+void
+nucomp_canonicalization(int f)
+{
+    canonicalization = f;
+}
+#endif
+
 inline static void
 nucomp_real_check(VALUE num)
 {
@@ -387,81 +377,73 @@
       case T_RATIONAL:
 	break;
       default:
-	rb_raise(rb_eArgError, "not a real");
+	if (!k_numeric_p(num) || !f_real_p(num))
+	    rb_raise(rb_eArgError, "not a real");
     }
 }
 
 inline static VALUE
-nucomp_s_canonicalize_internal(VALUE klass, VALUE real, VALUE image)
+nucomp_s_canonicalize_internal(VALUE klass, VALUE real, VALUE imag)
 {
+#ifdef CANON
 #define CL_CANON
 #ifdef CL_CANON
-    if (f_zero_p(image) && f_unify_p(klass) &&
-	!k_float_p(real) && !k_float_p(image))
+    if (k_exact_zero_p(imag) && canonicalization)
 	return real;
 #else
-    if (f_zero_p(image) && f_unify_p(klass))
+    if (f_zero_p(imag) && canonicalization)
 	return real;
 #endif
-    else if (f_scalar_p(real) && f_scalar_p(image))
-	return nucomp_s_new_internal(klass, real, image);
-    else if (f_scalar_p(real)) {
-	get_dat1(image);
+#endif
+    if (f_real_p(real) && f_real_p(imag))
+	return nucomp_s_new_internal(klass, real, imag);
+    else if (f_real_p(real)) {
+	get_dat1(imag);
 
 	return nucomp_s_new_internal(klass,
-				     f_sub(real, dat->image),
+				     f_sub(real, dat->imag),
 				     f_add(ZERO, dat->real));
     }
-    else if (f_scalar_p(image)) {
+    else if (f_real_p(imag)) {
 	get_dat1(real);
 
 	return nucomp_s_new_internal(klass,
 				     dat->real,
-				     f_add(dat->image, image));
+				     f_add(dat->imag, imag));
     }
     else {
-	get_dat2(real, image);
+	get_dat2(real, imag);
 
 	return nucomp_s_new_internal(klass,
-				     f_sub(adat->real, bdat->image),
-				     f_add(adat->image, bdat->real));
+				     f_sub(adat->real, bdat->imag),
+				     f_add(adat->imag, bdat->real));
     }
 }
 
-#if 0
+/*
+ * call-seq:
+ *    Complex.rect(real[, imag])         ->  complex
+ *    Complex.rectangular(real[, imag])  ->  complex
+ *
+ * Returns a complex object which denotes the given rectangular form.
+ */
 static VALUE
-nucomp_s_canonicalize(int argc, VALUE *argv, VALUE klass)
+nucomp_s_new(VALUE klass, SEL sel, int argc, VALUE *argv)
 {
-    VALUE real, image;
+    VALUE real, imag;
 
-    switch (rb_scan_args(argc, argv, "11", &real, &image)) {
+    switch (rb_scan_args(argc, argv, "11", &real, &imag)) {
       case 1:
-	image = ZERO;
+	nucomp_real_check(real);
+	imag = ZERO;
 	break;
-    }
-
-    nucomp_real_check(real);
-    nucomp_real_check(image);
-
-    return nucomp_s_canonicalize_internal(klass, real, image);
-}
-#endif
-
-static VALUE
-nucomp_s_new(int argc, VALUE *argv, VALUE klass)
-{
-    VALUE real, image;
-
-    switch (rb_scan_args(argc, argv, "11", &real, &image)) {
-      case 1:
-	image = ZERO;
+      default:
+	nucomp_real_check(real);
+	nucomp_real_check(imag);
 	break;
     }
 
-    nucomp_real_check(real);
-    nucomp_real_check(image);
-
-    return nucomp_s_canonicalize_internal(klass, real, image);
+    return nucomp_s_canonicalize_internal(klass, real, imag);
 }
 
 inline static VALUE
@@ -478,82 +460,98 @@
     return nucomp_s_canonicalize_internal(klass, x, y);
 }
 
+/*
+ * call-seq:
+ *    Complex(x[, y])  ->  numeric
+ *
+ * Returns x+i*y;
+ */
 static VALUE
-nucomp_f_complex(int argc, VALUE *argv, VALUE klass)
+nucomp_f_complex(VALUE klass, SEL sel, int argc, VALUE *argv)
 {
     return rb_funcall2(rb_cComplex, id_convert, argc, argv);
 }
 
-extern VALUE math_atan2(VALUE obj, VALUE x, VALUE y);
-extern VALUE math_cos(VALUE obj, VALUE x);
-extern VALUE math_cosh(VALUE obj, VALUE x);
-extern VALUE math_exp(VALUE obj, VALUE x);
-extern VALUE math_hypot(VALUE obj, VALUE x, VALUE y);
+#define imp1(n) \
+extern VALUE math_##n(VALUE obj, VALUE x);\
+inline static VALUE \
+m_##n##_bang(VALUE x)\
+{\
+    return math_##n(Qnil, x);\
+}
+
+#define imp2(n) \
+extern VALUE math_##n(VALUE obj, VALUE x, VALUE y);\
+inline static VALUE \
+m_##n##_bang(VALUE x, VALUE y)\
+{\
+    return math_##n(Qnil, x, y);\
+}
+
+imp2(atan2)
+imp1(cos)
+imp1(cosh)
+imp1(exp)
+imp2(hypot)
+
+#define m_hypot(x,y) m_hypot_bang(x,y)
+
 extern VALUE math_log(int argc, VALUE *argv);
-extern VALUE math_sin(VALUE obj, VALUE x);
-extern VALUE math_sinh(VALUE obj, VALUE x);
-extern VALUE math_sqrt(VALUE obj, VALUE x);
 
-#define m_atan2_bang(x,y) math_atan2(Qnil,x,y)
-#define m_cos_bang(x) math_cos(Qnil,x)
-#define m_cosh_bang(x) math_cosh(Qnil,x)
-#define m_exp_bang(x) math_exp(Qnil,x)
-#define m_hypot(x,y) math_hypot(Qnil,x,y)
-
 static VALUE
 m_log_bang(VALUE x)
 {
-  return math_log(1, &x);
+    return math_log(1, &x);
 }
 
-#define m_sin_bang(x) math_sin(Qnil,x)
-#define m_sinh_bang(x) math_sinh(Qnil,x)
-#define m_sqrt_bang(x) math_sqrt(Qnil,x)
+imp1(sin)
+imp1(sinh)
+imp1(sqrt)
 
 static VALUE
 m_cos(VALUE x)
 {
-    get_dat1(x);
-
-    if (f_generic_p(x))
+    if (f_real_p(x))
 	return m_cos_bang(x);
-    else
+    {
+	get_dat1(x);
 	return f_complex_new2(rb_cComplex,
 			      f_mul(m_cos_bang(dat->real),
-				    m_cosh_bang(dat->image)),
+				    m_cosh_bang(dat->imag)),
 			      f_mul(f_negate(m_sin_bang(dat->real)),
-				    m_sinh_bang(dat->image)));
+				    m_sinh_bang(dat->imag)));
+    }
 }
 
 static VALUE
 m_sin(VALUE x)
 {
-    get_dat1(x);
-
-    if (f_generic_p(x))
+    if (f_real_p(x))
 	return m_sin_bang(x);
-    else
+    {
+	get_dat1(x);
 	return f_complex_new2(rb_cComplex,
 			      f_mul(m_sin_bang(dat->real),
-				    m_cosh_bang(dat->image)),
+				    m_cosh_bang(dat->imag)),
 			      f_mul(m_cos_bang(dat->real),
-				    m_sinh_bang(dat->image)));
+				    m_sinh_bang(dat->imag)));
+    }
 }
 
+#if 0
 static VALUE
 m_sqrt(VALUE x)
 {
-    if (f_generic_p(x)) {
-	if (!f_negative_p(x))
+    if (f_real_p(x)) {
+	if (f_positive_p(x))
 	    return m_sqrt_bang(x);
-	else
-	    return f_complex_new2(rb_cComplex, ZERO, m_sqrt_bang(f_negate(x)));
+	return f_complex_new2(rb_cComplex, ZERO, m_sqrt_bang(f_negate(x)));
     }
     else {
 	get_dat1(x);
 
-	if (f_negative_p(dat->image))
-	    return f_conjugate(m_sqrt(f_conjugate(x)));
+	if (f_negative_p(dat->imag))
+	    return f_conj(m_sqrt(f_conj(x)));
 	else {
 	    VALUE a = f_abs(x);
 	    return f_complex_new2(rb_cComplex,
@@ -562,347 +560,540 @@
 	}
     }
 }
+#endif
 
+inline static VALUE
+f_complex_polar(VALUE klass, VALUE x, VALUE y)
+{
+    assert(!k_complex_p(x));
+    assert(!k_complex_p(y));
+    return nucomp_s_canonicalize_internal(klass,
+					  f_mul(x, m_cos(y)),
+					  f_mul(x, m_sin(y)));
+}
+
+/*
+ * call-seq:
+ *    Complex.polar(abs[, arg])  ->  complex
+ *
+ * Returns a complex object which denotes the given polar form.
+ */
 static VALUE
-nucomp_s_polar(VALUE klass, VALUE abs, VALUE arg)
+nucomp_s_polar(VALUE klass, SEL sel, int argc, VALUE *argv)
 {
-    return f_complex_new2(klass,
-			  f_mul(abs, m_cos(arg)),
-			  f_mul(abs, m_sin(arg)));
+    VALUE abs, arg;
+
+    switch (rb_scan_args(argc, argv, "11", &abs, &arg)) {
+      case 1:
+	nucomp_real_check(abs);
+	arg = ZERO;
+	break;
+      default:
+	nucomp_real_check(abs);
+	nucomp_real_check(arg);
+	break;
+    }
+    return f_complex_polar(klass, abs, arg);
 }
 
+/*
+ * call-seq:
+ *    cmp.real  ->  real
+ *
+ * Returns the real part.
+ */
 static VALUE
-nucomp_real(VALUE self)
+nucomp_real(VALUE self, SEL sel)
 {
     get_dat1(self);
     return dat->real;
 }
 
+/*
+ * call-seq:
+ *    cmp.imag       ->  real
+ *    cmp.imaginary  ->  real
+ *
+ * Returns the imaginary part.
+ */
 static VALUE
-nucomp_image(VALUE self)
+nucomp_imag(VALUE self, SEL sel)
 {
     get_dat1(self);
-    return dat->image;
+    return dat->imag;
 }
 
+/*
+ * call-seq:
+ *    -cmp  ->  complex
+ *
+ * Returns negation of the value.
+ */
 static VALUE
-nucomp_add(VALUE self, VALUE other)
+nucomp_negate(VALUE self, SEL sel)
 {
-    switch (TYPE(other)) {
-      case T_FIXNUM:
-      case T_BIGNUM:
-      case T_FLOAT:
-      case T_RATIONAL:
-	{
-	    get_dat1(self);
+  get_dat1(self);
+  return f_complex_new2(CLASS_OF(self),
+			f_negate(dat->real), f_negate(dat->imag));
+}
 
-	    return f_complex_new2(CLASS_OF(self),
-				  f_add(dat->real, other), dat->image);
-	}
-      case T_COMPLEX:
-	{
-	    VALUE real, image;
+inline static VALUE
+f_addsub(VALUE self, VALUE other,
+	 VALUE (*func)(VALUE, VALUE), ID id)
+{
+    if (k_complex_p(other)) {
+	VALUE real, imag;
 
-	    get_dat2(self, other);
+	get_dat2(self, other);
 
-	    real = f_add(adat->real, bdat->real);
-	    image = f_add(adat->image, bdat->image);
+	real = (*func)(adat->real, bdat->real);
+	imag = (*func)(adat->imag, bdat->imag);
 
-	    return f_complex_new2(CLASS_OF(self), real, image);
-	}
-      default:
-	return rb_num_coerce_bin(self, other, '+');
+	return f_complex_new2(CLASS_OF(self), real, imag);
     }
+    if (k_numeric_p(other) && f_real_p(other)) {
+	get_dat1(self);
+
+	return f_complex_new2(CLASS_OF(self),
+			      (*func)(dat->real, other), dat->imag);
+    }
+    return rb_num_coerce_bin(self, other, id);
 }
 
+/*
+ * call-seq:
+ *    cmp + numeric  ->  complex
+ *
+ * Performs addition.
+ */
 static VALUE
-nucomp_sub(VALUE self, VALUE other)
+nucomp_add(VALUE self, SEL sel, VALUE other)
 {
-    switch (TYPE(other)) {
-      case T_FIXNUM:
-      case T_BIGNUM:
-      case T_FLOAT:
-      case T_RATIONAL:
-	{
-	    get_dat1(self);
+    return f_addsub(self, other, f_add, '+');
+}
 
-	    return f_complex_new2(CLASS_OF(self),
-				  f_sub(dat->real, other), dat->image);
-	}
-      case T_COMPLEX:
-	{
-	    VALUE real, image;
-
-	    get_dat2(self, other);
-
-	    real = f_sub(adat->real, bdat->real);
-	    image = f_sub(adat->image, bdat->image);
-
-	    return f_complex_new2(CLASS_OF(self), real, image);
-	}
-      default:
-	return rb_num_coerce_bin(self, other, '-');
-    }
+/*
+ * call-seq:
+ *    cmp - numeric  ->  complex
+ *
+ * Performs subtraction.
+ */
+static VALUE
+nucomp_sub(VALUE self, SEL sel, VALUE other)
+{
+    return f_addsub(self, other, f_sub, '-');
 }
 
+/*
+ * call-seq:
+ *    cmp * numeric  ->  complex
+ *
+ * Performs multiplication.
+ */
 static VALUE
-nucomp_mul(VALUE self, VALUE other)
+nucomp_mul(VALUE self, SEL sel, VALUE other)
 {
-    switch (TYPE(other)) {
-      case T_FIXNUM:
-      case T_BIGNUM:
-      case T_FLOAT:
-      case T_RATIONAL:
-	{
-	    get_dat1(self);
+    if (k_complex_p(other)) {
+	VALUE real, imag;
 
-	    return f_complex_new2(CLASS_OF(self),
-				  f_mul(dat->real, other),
-				  f_mul(dat->image, other));
-	}
-      case T_COMPLEX:
-	{
-	    VALUE real, image;
+	get_dat2(self, other);
 
-	    get_dat2(self, other);
+	real = f_sub(f_mul(adat->real, bdat->real),
+		     f_mul(adat->imag, bdat->imag));
+	imag = f_add(f_mul(adat->real, bdat->imag),
+		     f_mul(adat->imag, bdat->real));
 
-	    real = f_sub(f_mul(adat->real, bdat->real),
-			 f_mul(adat->image, bdat->image));
-	    image = f_add(f_mul(adat->real, bdat->image),
-			  f_mul(adat->image, bdat->real));
+	return f_complex_new2(CLASS_OF(self), real, imag);
+    }
+    if (k_numeric_p(other) && f_real_p(other)) {
+	get_dat1(self);
 
-	    return f_complex_new2(CLASS_OF(self), real, image);
-	}
-      default:
-	return rb_num_coerce_bin(self, other, '*');
+	return f_complex_new2(CLASS_OF(self),
+			      f_mul(dat->real, other),
+			      f_mul(dat->imag, other));
     }
+    return rb_num_coerce_bin(self, other, '*');
 }
 
-static VALUE
-nucomp_div(VALUE self, VALUE other)
+inline static VALUE
+f_divide(VALUE self, VALUE other,
+	 VALUE (*func)(VALUE, VALUE), ID id)
 {
-    switch (TYPE(other)) {
-      case T_FIXNUM:
-      case T_BIGNUM:
-      case T_FLOAT:
-      case T_RATIONAL:
-	{
-	    get_dat1(self);
+    if (k_complex_p(other)) {
+	int flo;
+	get_dat2(self, other);
 
+	flo = (k_float_p(adat->real) || k_float_p(adat->imag) ||
+	       k_float_p(bdat->real) || k_float_p(bdat->imag));
+
+	if (f_gt_p(f_abs(bdat->real), f_abs(bdat->imag))) {
+	    VALUE r, n;
+
+	    r = (*func)(bdat->imag, bdat->real);
+	    n = f_mul(bdat->real, f_add(ONE, f_mul(r, r)));
+	    if (flo)
+		return f_complex_new2(CLASS_OF(self),
+				      (*func)(self, n),
+				      (*func)(f_negate(f_mul(self, r)), n));
 	    return f_complex_new2(CLASS_OF(self),
-				  f_div(dat->real, other),
-				  f_div(dat->image, other));
+				  (*func)(f_add(adat->real,
+						f_mul(adat->imag, r)), n),
+				  (*func)(f_sub(adat->imag,
+						f_mul(adat->real, r)), n));
 	}
-      case T_COMPLEX:
-	{
-	    get_dat2(self, other);
+	else {
+	    VALUE r, n;
 
-	    if (TYPE(adat->real)  == T_FLOAT ||
-		TYPE(adat->image) == T_FLOAT ||
-		TYPE(bdat->real)  == T_FLOAT ||
-		TYPE(bdat->image) == T_FLOAT) {
-		VALUE magn = m_hypot(bdat->real, bdat->image);
-		VALUE tmp = f_complex_new_bang2(CLASS_OF(self),
-						f_div(bdat->real, magn),
-						f_div(bdat->image, magn));
-		return f_div(f_mul(self, f_conjugate(tmp)), magn);
-	    }
-	    return f_div(f_mul(self, f_conjugate(other)), f_abs2(other));
+	    r = (*func)(bdat->real, bdat->imag);
+	    n = f_mul(bdat->imag, f_add(ONE, f_mul(r, r)));
+	    if (flo)
+		return f_complex_new2(CLASS_OF(self),
+				      (*func)(f_mul(self, r), n),
+				      (*func)(f_negate(self), n));
+	    return f_complex_new2(CLASS_OF(self),
+				  (*func)(f_add(f_mul(adat->real, r),
+						adat->imag), n),
+				  (*func)(f_sub(f_mul(adat->imag, r),
+						adat->real), n));
 	}
-      default:
-	return rb_num_coerce_bin(self, other, '/');
     }
+    if (k_numeric_p(other) && f_real_p(other)) {
+	get_dat1(self);
+
+	return f_complex_new2(CLASS_OF(self),
+			      (*func)(dat->real, other),
+			      (*func)(dat->imag, other));
+    }
+    return rb_num_coerce_bin(self, other, id);
 }
 
+#define rb_raise_zerodiv() rb_raise(rb_eZeroDivError, "divided by 0")
+
+/*
+ * call-seq:
+ *    cmp / numeric     ->  complex
+ *    cmp.quo(numeric)  ->  complex
+ *
+ * Performs division.
+ *
+ * For example:
+ *
+ *     Complex(10.0) / 3  #=> (3.3333333333333335+(0/1)*i)
+ *     Complex(10)   / 3  #=> ((10/3)+(0/1)*i)  # not (3+0i)
+ */
 static VALUE
-nucomp_quo(VALUE self, VALUE other)
+nucomp_div(VALUE self, SEL sel, VALUE other)
 {
-    get_dat1(self);
+    return f_divide(self, other, f_quo, id_quo);
+}
 
-    return f_div(f_complex_new2(CLASS_OF(self),
-				f_quo(dat->real, ONE),
-				f_quo(dat->image, ONE)), other);
+#define nucomp_quo nucomp_div
+
+/*
+ * call-seq:
+ *    cmp.fdiv(numeric)  ->  complex
+ *
+ * Performs division as each part is a float, never returns a float.
+ *
+ * For example:
+ *
+ *     Complex(11,22).fdiv(3)  #=> (3.6666666666666665+7.333333333333333i)
+ */
+static VALUE
+nucomp_fdiv(VALUE self, SEL sel, VALUE other)
+{
+    return f_divide(self, other, f_fdiv, id_fdiv);
 }
 
 static VALUE
-nucomp_fdiv(VALUE self, VALUE other)
+m_log(VALUE x)
 {
-    get_dat1(self);
+    if (f_real_p(x) && f_positive_p(x))
+	return m_log_bang(x);
+    return rb_complex_new2(m_log_bang(f_abs(x)), f_arg(x));
+}
 
-    return f_div(f_complex_new2(CLASS_OF(self),
-				f_to_f(dat->real),
-				f_to_f(dat->image)), other);
+static VALUE
+m_exp(VALUE x)
+{
+    VALUE ere, im;
+
+    if (f_real_p(x))
+	return m_exp_bang(x);
+    ere = m_exp_bang(f_real(x));
+    im = f_imag(x);
+    return rb_complex_new2(f_mul(ere, m_cos_bang(im)),
+			   f_mul(ere, m_sin_bang(im)));
 }
 
+VALUE
+rb_fexpt(VALUE x, VALUE y)
+{
+    if (f_zero_p(x) || (!k_float_p(x) && !k_float_p(y)))
+	return f_expt(x, y);
+    return m_exp(f_mul(m_log(x), y));
+}
+
+inline static VALUE
+f_reciprocal(VALUE x)
+{
+    return f_quo(ONE, x);
+}
+
+/*
+ * call-seq:
+ *    cmp ** numeric  ->  complex
+ *
+ * Performs exponentiation.
+ *
+ * For example:
+ *
+ *     Complex('i') ** 2             #=> (-1+0i)
+ *     Complex(-8) ** Rational(1,3)  #=> (1.0000000000000002+1.7320508075688772i)
+ */
 static VALUE
-nucomp_expt(VALUE self, VALUE other)
+nucomp_expt(VALUE self, SEL sel, VALUE other)
 {
-    if (f_zero_p(other))
+    if (k_exact_zero_p(other))
 	return f_complex_new_bang1(CLASS_OF(self), ONE);
 
     if (k_rational_p(other) && f_one_p(f_denominator(other)))
-	other = f_numerator(other); /* good? */
+	other = f_numerator(other); /* c14n */
 
-    switch (TYPE(other)) {
-      case T_FIXNUM:
-      case T_BIGNUM:
+    if (k_complex_p(other)) {
+	get_dat1(other);
+
+	if (k_exact_zero_p(dat->imag))
+	    other = dat->real; /* c14n */
+    }
+
+    if (k_complex_p(other)) {
+	VALUE r, theta, nr, ntheta;
+
+	get_dat1(other);
+
+	r = f_abs(self);
+	theta = f_arg(self);
+
+	nr = m_exp_bang(f_sub(f_mul(dat->real, m_log_bang(r)),
+			      f_mul(dat->imag, theta)));
+	ntheta = f_add(f_mul(theta, dat->real),
+		       f_mul(dat->imag, m_log_bang(r)));
+	return f_complex_polar(CLASS_OF(self), nr, ntheta);
+    }
+    if (k_fixnum_p(other)) {
 	if (f_gt_p(other, ZERO)) {
-	    VALUE x, z, n;
+	    VALUE x, z;
+	    long n;
 
 	    x = self;
 	    z = x;
-	    n = f_sub(other, ONE);
+	    n = FIX2LONG(other) - 1;
 
-	    while (!f_zero_p(n)) {
-		VALUE a;
+	    while (n) {
+		long q, r;
 
-		while (a = f_divmod(n, TWO),
-		       f_zero_p(RARRAY_AT(a, 1))) {
+		while (1) {
 		    get_dat1(x);
 
+		    q = n / 2;
+		    r = n % 2;
+
+		    if (r)
+			break;
+
 		    x = f_complex_new2(CLASS_OF(self),
 				       f_sub(f_mul(dat->real, dat->real),
-					     f_mul(dat->image, dat->image)),
-				       f_mul(f_mul(TWO, dat->real), dat->image));
-		    n = RARRAY_AT(a, 0);
+					     f_mul(dat->imag, dat->imag)),
+				       f_mul(f_mul(TWO, dat->real), dat->imag));
+		    n = q;
 		}
 		z = f_mul(z, x);
-		n = f_sub(n, ONE);
+		n--;
 	    }
 	    return z;
 	}
-	else {
-	    return f_expt(f_div(f_to_r(ONE), self), f_negate(other));
-	}
-      case T_FLOAT:
-      case T_RATIONAL:
-	{
-	    VALUE a, r, theta;
+	return f_expt(f_reciprocal(self), f_negate(other));
+    }
+    if (k_numeric_p(other) && f_real_p(other)) {
+	VALUE r, theta;
 
-	    a = f_polar(self);
-	    r = RARRAY_AT(a, 0);
-	    theta = RARRAY_AT(a, 1);
-	    return nucomp_s_polar(CLASS_OF(self), f_expt(r, other),
-				  f_mul(theta, other));
-	}
-      case T_COMPLEX:
-	{
-	    VALUE a, r, theta, ore, oim, nr, ntheta;
+	if (k_bignum_p(other))
+	    rb_warn("in a**b, b may be too big");
 
-	    get_dat1(other);
+	r = f_abs(self);
+	theta = f_arg(self);
 
-	    a = f_polar(self);
-	    r = RARRAY_AT(a, 0);
-	    theta = RARRAY_AT(a, 1);
-
-	    ore = dat->real;
-	    oim = dat->image;
-	    nr = m_exp_bang(f_sub(f_mul(ore, m_log_bang(r)),
-				  f_mul(oim, theta)));
-	    ntheta = f_add(f_mul(theta, ore), f_mul(oim, m_log_bang(r)));
-	    return nucomp_s_polar(CLASS_OF(self), nr, ntheta);
-	}
-      default:
-	return rb_num_coerce_bin(self, other, id_expt);
+	return f_complex_polar(CLASS_OF(self), f_expt(r, other),
+			       f_mul(theta, other));
     }
+    return rb_num_coerce_bin(self, other, id_expt);
 }
 
+/*
+ * call-seq:
+ *    cmp == object  ->  true or false
+ *
+ * Returns true if cmp equals object numerically.
+ */
 static VALUE
-nucomp_equal_p(VALUE self, VALUE other)
+nucomp_eqeq_p(VALUE self, SEL sel, VALUE other)
 {
-    switch (TYPE(other)) {
-      case T_FIXNUM:
-      case T_BIGNUM:
-      case T_FLOAT:
-      case T_RATIONAL:
-	{
-	    get_dat1(self);
+    if (k_complex_p(other)) {
+	get_dat2(self, other);
 
-	    return f_boolcast(f_equal_p(dat->real, other) && f_zero_p(dat->image));
-	}
-      case T_COMPLEX:
-	{
-	    get_dat2(self, other);
+	return f_boolcast(f_eqeq_p(adat->real, bdat->real) &&
+			  f_eqeq_p(adat->imag, bdat->imag));
+    }
+    if (k_numeric_p(other) && f_real_p(other)) {
+	get_dat1(self);
 
-	    return f_boolcast(f_equal_p(adat->real, bdat->real) &&
-			      f_equal_p(adat->image, bdat->image));
-	}
-      default:
-	return f_equal_p(other, self);
+	return f_boolcast(f_eqeq_p(dat->real, other) && f_zero_p(dat->imag));
     }
+    return f_eqeq_p(other, self);
 }
 
+/* :nodoc: */
 static VALUE
-nucomp_coerce(VALUE self, VALUE other)
+nucomp_coerce(VALUE self, SEL sel, VALUE other)
 {
-    switch (TYPE(other)) {
-      case T_FIXNUM:
-      case T_BIGNUM:
-      case T_FLOAT:
-      case T_RATIONAL:
+    if (k_numeric_p(other) && f_real_p(other))
 	return rb_assoc_new(f_complex_new_bang1(CLASS_OF(self), other), self);
-    }
+    if (TYPE(other) == T_COMPLEX)
+	return rb_assoc_new(other, self);
 
     rb_raise(rb_eTypeError, "%s can't be coerced into %s",
 	     rb_obj_classname(other), rb_obj_classname(self));
     return Qnil;
 }
 
+/*
+ * call-seq:
+ *    cmp.abs        ->  real
+ *    cmp.magnitude  ->  real
+ *
+ * Returns the absolute part of its polar form.
+ */
 static VALUE
-nucomp_abs(VALUE self)
+nucomp_abs(VALUE self, SEL sel)
 {
     get_dat1(self);
-    return m_hypot(dat->real, dat->image);
+
+    if (f_zero_p(dat->real)) {
+	VALUE a = f_abs(dat->imag);
+	if (k_float_p(dat->real) && !k_float_p(dat->imag))
+	    a = f_to_f(a);
+	return a;
+    }
+    if (f_zero_p(dat->imag)) {
+	VALUE a = f_abs(dat->real);
+	if (!k_float_p(dat->real) && k_float_p(dat->imag))
+	    a = f_to_f(a);
+	return a;
+    }
+    return m_hypot(dat->real, dat->imag);
 }
 
+/*
+ * call-seq:
+ *    cmp.abs2  ->  real
+ *
+ * Returns square of the absolute value.
+ */
 static VALUE
-nucomp_abs2(VALUE self)
+nucomp_abs2(VALUE self, SEL sel)
 {
     get_dat1(self);
     return f_add(f_mul(dat->real, dat->real),
-		 f_mul(dat->image, dat->image));
+		 f_mul(dat->imag, dat->imag));
 }
 
+/*
+ * call-seq:
+ *    cmp.arg    ->  float
+ *    cmp.angle  ->  float
+ *    cmp.phase  ->  float
+ *
+ * Returns the angle part of its polar form.
+ */
 static VALUE
-nucomp_arg(VALUE self)
+nucomp_arg(VALUE self, SEL sel)
 {
     get_dat1(self);
-    return m_atan2_bang(dat->image, dat->real);
+    return m_atan2_bang(dat->imag, dat->real);
 }
 
+/*
+ * call-seq:
+ *    cmp.rect         ->  array
+ *    cmp.rectangular  ->  array
+ *
+ * Returns an array; [cmp.real, cmp.imag].
+ */
 static VALUE
-nucomp_polar(VALUE self)
+nucomp_rect(VALUE self, SEL sel)
 {
+    get_dat1(self);
+    return rb_assoc_new(dat->real, dat->imag);
+}
+
+/*
+ * call-seq:
+ *    cmp.polar  ->  array
+ *
+ * Returns an array; [cmp.abs, cmp.arg].
+ */
+static VALUE
+nucomp_polar(VALUE self, SEL sel)
+{
     return rb_assoc_new(f_abs(self), f_arg(self));
 }
 
+/*
+ * call-seq:
+ *    cmp.conj       ->  complex
+ *    cmp.conjucate  ->  complex
+ *
+ * Returns the complex conjucate.
+ */
 static VALUE
-nucomp_conjugate(VALUE self)
+nucomp_conj(VALUE self, SEL sel)
 {
     get_dat1(self);
-    return f_complex_new2(CLASS_OF(self), dat->real, f_negate(dat->image));
+    return f_complex_new2(CLASS_OF(self), dat->real, f_negate(dat->imag));
 }
 
 #if 0
+/* :nodoc: */
 static VALUE
-nucomp_real_p(VALUE self)
+nucomp_true(VALUE self)
 {
-    return Qfalse;
+    return Qtrue;
 }
+#endif
 
+/*
+ * call-seq:
+ *    cmp.real?  ->  false
+ *
+ * Returns false.
+ */
 static VALUE
-nucomp_complex_p(VALUE self)
+nucomp_false(VALUE self, SEL sel)
 {
-    return Qtrue;
+    return Qfalse;
 }
 
+#if 0
+/* :nodoc: */
 static VALUE
 nucomp_exact_p(VALUE self)
 {
     get_dat1(self);
-    return f_boolcast(f_exact_p(dat->real) && f_exact_p(dat->image));
+    return f_boolcast(k_exact_p(dat->real) && k_exact_p(dat->imag));
 }
 
+/* :nodoc: */
 static VALUE
 nucomp_inexact_p(VALUE self)
 {
@@ -910,17 +1101,45 @@
 }
 #endif
 
-extern VALUE rb_lcm(VALUE x, VALUE y);
+extern VALUE rb_lcm(VALUE x, SEL sel, VALUE y);
 
+/*
+ * call-seq:
+ *    cmp.denominator  ->  integer
+ *
+ * Returns the denominator (lcm of both denominator, real and imag).
+ *
+ * See numerator.
+ */
 static VALUE
-nucomp_denominator(VALUE self)
+nucomp_denominator(VALUE self, SEL sel)
 {
     get_dat1(self);
-    return rb_lcm(f_denominator(dat->real), f_denominator(dat->image));
+    return rb_lcm(f_denominator(dat->real), 0, f_denominator(dat->imag));
 }
 
+/*
+ * call-seq:
+ *    cmp.numerator  ->  numeric
+ *
+ * Returns the numerator.
+ *
+ * For example:
+ *
+ *        1   2       3+4i  <-  numerator
+ *        - + -i  ->  ----
+ *        2   3        6    <-  denominator
+ *
+ *    c = Complex('1/2+2/3i')  #=> ((1/2)+(2/3)*i)
+ *    n = c.numerator          #=> (3+4i)
+ *    d = c.denominator        #=> 6
+ *    n / d                    #=> ((1/2)+(2/3)*i)
+ *    Complex(Rational(n.real, d), Rational(n.imag, d))
+ *                             #=> ((1/2)+(2/3)*i)
+ * See denominator.
+ */
 static VALUE
-nucomp_numerator(VALUE self)
+nucomp_numerator(VALUE self, SEL sel)
 {
     VALUE cd;
 
@@ -930,17 +1149,41 @@
     return f_complex_new2(CLASS_OF(self),
 			  f_mul(f_numerator(dat->real),
 				f_div(cd, f_denominator(dat->real))),
-			  f_mul(f_numerator(dat->image),
-				f_div(cd, f_denominator(dat->image))));
+			  f_mul(f_numerator(dat->imag),
+				f_div(cd, f_denominator(dat->imag))));
 }
 
+/* :nodoc: */
 static VALUE
-nucomp_hash(VALUE self)
+nucomp_hash(VALUE self, SEL sel)
 {
+    long v, h[2];
+    VALUE n;
+
     get_dat1(self);
-    return f_xor(dat->real, dat->image);
+    n = rb_hash(dat->real);
+    h[0] = NUM2LONG(n);
+    n = rb_hash(dat->imag);
+    h[1] = NUM2LONG(n);
+    v = rb_memhash(h, sizeof(h));
+    return LONG2FIX(v);
 }
 
+/* :nodoc: */
+static VALUE
+nucomp_eql_p(VALUE self, SEL sel, VALUE other)
+{
+    if (k_complex_p(other)) {
+	get_dat2(self, other);
+
+	return f_boolcast((CLASS_OF(adat->real) == CLASS_OF(bdat->real)) &&
+			  (CLASS_OF(adat->imag) == CLASS_OF(bdat->imag)) &&
+			  f_eqeq_p(self, other));
+
+    }
+    return Qfalse;
+}
+
 #ifndef HAVE_SIGNBIT
 #ifdef signbit
 #define HAVE_SIGNBIT 1
@@ -951,94 +1194,99 @@
 f_signbit(VALUE x)
 {
     switch (TYPE(x)) {
-      case T_FLOAT:
+      case T_FLOAT: {
 #ifdef HAVE_SIGNBIT
-	return f_boolcast(signbit(RFLOAT_VALUE(x)));
+	double f = RFLOAT_VALUE(x);
+	return f_boolcast(!isnan(f) && signbit(f));
 #else
-	{
-	    char s[2];
+	char s[2];
+	double f = RFLOAT_VALUE(x);
 
-	    (void)snprintf(s, sizeof s, "%.0f", RFLOAT_VALUE(x));
-
-	    return f_boolcast(s[0] == '-');
-	}
+	if (isnan(f)) return Qfalse;
+	(void)snprintf(s, sizeof s, "%.0f", f);
+	return f_boolcast(s[0] == '-');
 #endif
+      }
     }
     return f_negative_p(x);
 }
 
 inline static VALUE
-f_tzero_p(VALUE x)
-{
-    return f_boolcast(f_zero_p(x) && !f_signbit(x));
-}
-
-inline static VALUE
 f_tpositive_p(VALUE x)
 {
     return f_boolcast(!f_signbit(x));
 }
 
 static VALUE
-nucomp_to_s(VALUE self)
+f_format(VALUE self, VALUE (*func)(VALUE))
 {
-    VALUE s, rezero, impos;
+    VALUE s, impos;
 
     get_dat1(self);
 
-    rezero = f_tzero_p(dat->real);
-    impos = f_tpositive_p(dat->image);
+    impos = f_tpositive_p(dat->imag);
 
-    if (rezero)
-	s = rb_str_new2("");
-    else {
-	s = f_to_s(dat->real);
-	rb_str_cat2(s, !impos ? "-" : "+");
-    }
+    s = (*func)(dat->real);
+    rb_str_cat2(s, !impos ? "-" : "+");
 
-    if (k_rational_p(dat->image) &&
-	!f_one_p(f_denominator(dat->image))) {
-	rb_str_cat2(s, "(");
-	rb_str_concat(s, f_to_s(rezero ? dat->image : f_abs(dat->image)));
-	rb_str_cat2(s, ")i");
-    }
-    else {
-	rb_str_concat(s, f_to_s(rezero ? dat->image : f_abs(dat->image)));
-	rb_str_cat2(s, "i");
-    }
+    rb_str_concat(s, (*func)(f_abs(dat->imag)));
+    if (!rb_isdigit(RSTRING_PTR(s)[RSTRING_LEN(s) - 1]))
+	rb_str_cat2(s, "*");
+    rb_str_cat2(s, "i");
 
     return s;
 }
 
+/*
+ * call-seq:
+ *    cmp.to_s  ->  string
+ *
+ * Returns the value as a string.
+ */
 static VALUE
-nucomp_inspect(VALUE self)
+nucomp_to_s(VALUE self, SEL sel)
 {
+    return f_format(self, f_to_s);
+}
+
+/*
+ * call-seq:
+ *    cmp.inspect  ->  string
+ *
+ * Returns the value as a string for inspection.
+ */
+static VALUE
+nucomp_inspect(VALUE self, SEL sel)
+{
     VALUE s;
 
-    get_dat1(self);
-
-    s = rb_str_new2("Complex(");
-    rb_str_concat(s, f_inspect(dat->real));
-    rb_str_cat2(s, ", ");
-    rb_str_concat(s, f_inspect(dat->image));
+    s = rb_usascii_str_new2("(");
+    rb_str_concat(s, f_format(self, f_inspect));
     rb_str_cat2(s, ")");
 
     return s;
 }
 
+/* :nodoc: */
 static VALUE
-nucomp_marshal_dump(VALUE self)
+nucomp_marshal_dump(VALUE self, SEL sel)
 {
+    VALUE a;
     get_dat1(self);
-    return rb_assoc_new(dat->real, dat->image);
+
+    a = rb_assoc_new(dat->real, dat->imag);
+    rb_copy_generic_ivar(a, self);
+    return a;
 }
 
+/* :nodoc: */
 static VALUE
-nucomp_marshal_load(VALUE self, VALUE a)
+nucomp_marshal_load(VALUE self, SEL sel, VALUE a)
 {
     get_dat1(self);
-    dat->real = RARRAY_AT(a, 0);
-    dat->image = RARRAY_AT(a, 1);
+    dat->real = RARRAY_PTR(a)[0];
+    dat->imag = RARRAY_PTR(a)[1];
+    rb_copy_generic_ivar(self, a);
     return self;
 }
 
@@ -1056,29 +1304,35 @@
     return nucomp_s_canonicalize_internal(rb_cComplex, x, y);
 }
 
-static VALUE nucomp_s_convert(int argc, VALUE *argv, VALUE klass);
+VALUE
+rb_complex_polar(VALUE x, VALUE y)
+{
+    return f_complex_polar(rb_cComplex, x, y);
+}
 
+static VALUE nucomp_s_convert(VALUE klass, SEL sel, int argc, VALUE *argv);
+
 VALUE
 rb_Complex(VALUE x, VALUE y)
 {
     VALUE a[2];
     a[0] = x;
     a[1] = y;
-    return nucomp_s_convert(2, a, rb_cComplex);
+    return nucomp_s_convert(rb_cComplex, NULL, 2, a);
 }
 
+/*
+ * call-seq:
+ *    cmp.to_i  ->  integer
+ *
+ * Returns the value as an integer if possible.
+ */
 static VALUE
-nucomp_scalar_p(VALUE self)
+nucomp_to_i(VALUE self, SEL sel)
 {
-    return Qfalse;
-}
-
-static VALUE
-nucomp_to_i(VALUE self)
-{
     get_dat1(self);
 
-    if (k_float_p(dat->image) || !f_zero_p(dat->image)) {
+    if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) {
 	VALUE s = f_to_s(self);
 	rb_raise(rb_eRangeError, "can't convert %s into Integer",
 		 StringValuePtr(s));
@@ -1086,12 +1340,18 @@
     return f_to_i(dat->real);
 }
 
+/*
+ * call-seq:
+ *    cmp.to_f  ->  float
+ *
+ * Returns the value as a float if possible.
+ */
 static VALUE
-nucomp_to_f(VALUE self)
+nucomp_to_f(VALUE self, SEL sel)
 {
     get_dat1(self);
 
-    if (k_float_p(dat->image) || !f_zero_p(dat->image)) {
+    if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) {
 	VALUE s = f_to_s(self);
 	rb_raise(rb_eRangeError, "can't convert %s into Float",
 		 StringValuePtr(s));
@@ -1099,12 +1359,18 @@
     return f_to_f(dat->real);
 }
 
+/*
+ * call-seq:
+ *    cmp.to_r  ->  rational
+ *
+ * Returns the value as a rational if possible.
+ */
 static VALUE
-nucomp_to_r(VALUE self)
+nucomp_to_r(VALUE self, SEL sel)
 {
     get_dat1(self);
 
-    if (k_float_p(dat->image) || !f_zero_p(dat->image)) {
+    if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) {
 	VALUE s = f_to_s(self);
 	rb_raise(rb_eRangeError, "can't convert %s into Rational",
 		 StringValuePtr(s));
@@ -1112,67 +1378,79 @@
     return f_to_r(dat->real);
 }
 
+/*
+ * call-seq:
+ *    nil.to_c  ->  (0+0i)
+ *
+ * Returns zero as a complex.
+ */
 static VALUE
-nilclass_to_c(VALUE self)
+nilclass_to_c(VALUE self, SEL sel)
 {
     return rb_complex_new1(INT2FIX(0));
 }
 
+/*
+ * call-seq:
+ *    num.to_c  ->  complex
+ *
+ * Returns the value as a complex.
+ */
 static VALUE
-numeric_to_c(VALUE self)
+numeric_to_c(VALUE self, SEL sel)
 {
     return rb_complex_new1(self);
 }
 
-static VALUE comp_pat1, comp_pat2, a_slash, a_dot_and_an_e,
-    image_garbages_pat, null_string, underscores_pat, an_underscore;
+static VALUE comp_pat0, comp_pat1, comp_pat2, a_slash, a_dot_and_an_e,
+    null_string, underscores_pat, an_underscore;
 
-#define DIGITS "(?:\\d(?:_\\d|\\d)*)"
+#define WS "\\s*"
+#define DIGITS "(?:[0-9](?:_[0-9]|[0-9])*)"
 #define NUMERATOR "(?:" DIGITS "?\\.)?" DIGITS "(?:[eE][-+]?" DIGITS ")?"
-#define DENOMINATOR "[-+]?" DIGITS
+#define DENOMINATOR DIGITS
 #define NUMBER "[-+]?" NUMERATOR "(?:\\/" DENOMINATOR ")?"
 #define NUMBERNOS NUMERATOR "(?:\\/" DENOMINATOR ")?"
-#define PATTERN1 "\\A(" NUMBER "|\\(" NUMBER "\\))[iIjJ]"
-#define PATTERN2 "\\A(" NUMBER ")([-+](?:" NUMBERNOS "|\\(" NUMBER "\\))[iIjJ])?"
+#define PATTERN0 "\\A" WS "(" NUMBER ")@(" NUMBER ")" WS
+#define PATTERN1 "\\A" WS "([-+])?(" NUMBER ")?[iIjJ]" WS
+#define PATTERN2 "\\A" WS "(" NUMBER ")(([-+])(" NUMBERNOS ")?[iIjJ])?" WS
 
 static void
 make_patterns(void)
 {
-    static char comp_pat1_source[] = PATTERN1;
-    static char comp_pat2_source[] = PATTERN2;
-    static char image_garbages_pat_source[] = "[+\\(\\)iIjJ]";
-    static char underscores_pat_source[] = "_+";
+    static const char comp_pat0_source[] = PATTERN0;
+    static const char comp_pat1_source[] = PATTERN1;
+    static const char comp_pat2_source[] = PATTERN2;
+    static const char underscores_pat_source[] = "_+";
 
+    if (comp_pat0) return;
+
+    comp_pat0 = rb_reg_new(comp_pat0_source, sizeof comp_pat0_source - 1, 0);
+    rb_register_mark_object(comp_pat0);
+
     comp_pat1 = rb_reg_new(comp_pat1_source, sizeof comp_pat1_source - 1, 0);
-    rb_global_variable(&comp_pat1);
+    rb_register_mark_object(comp_pat1);
 
     comp_pat2 = rb_reg_new(comp_pat2_source, sizeof comp_pat2_source - 1, 0);
-    rb_global_variable(&comp_pat2);
+    rb_register_mark_object(comp_pat2);
 
-    a_slash = rb_str_new2("/");
-    rb_global_variable(&a_slash);
+    a_slash = rb_usascii_str_new2("/");
+    rb_register_mark_object(a_slash);
 
-    a_dot_and_an_e = rb_str_new2(".eE");
-    rb_global_variable(&a_dot_and_an_e);
+    a_dot_and_an_e = rb_usascii_str_new2(".eE");
+    rb_register_mark_object(a_dot_and_an_e);
 
-    image_garbages_pat = rb_reg_new(image_garbages_pat_source,
-				    sizeof image_garbages_pat_source - 1, 0);
-    rb_global_variable(&image_garbages_pat);
+    null_string = rb_usascii_str_new2("");
+    rb_register_mark_object(null_string);
 
-    null_string = rb_str_new2("");
-    rb_global_variable(&null_string);
-
     underscores_pat = rb_reg_new(underscores_pat_source,
 				 sizeof underscores_pat_source - 1, 0);
-    rb_global_variable(&underscores_pat);
+    rb_register_mark_object(underscores_pat);
 
-    an_underscore = rb_str_new2("_");
-    rb_global_variable(&an_underscore);
+    an_underscore = rb_usascii_str_new2("_");
+    rb_register_mark_object(an_underscore);
 }
 
-#define id_strip rb_intern("strip")
-#define f_strip(x) rb_funcall(x, id_strip, 0)
-
 #define id_match rb_intern("match")
 #define f_match(x,y) rb_funcall(x, id_match, 1, y)
 
@@ -1199,27 +1477,59 @@
 {
     VALUE s;
 
-    s = f_strip(self);
+    s = self;
 
     if (RSTRING_LEN(s) == 0)
 	return rb_assoc_new(Qnil, self);
 
     {
 	VALUE m, sr, si, re, r, i;
+	int po;
 
-	m = f_match(comp_pat1, s);
+	m = f_match(comp_pat0, s);
 	if (!NIL_P(m)) {
-	    sr = Qnil;
-	    si = f_aref(m, INT2FIX(1));
-	    re = f_post_match(m);
+	  sr = f_aref(m, INT2FIX(1));
+	  si = f_aref(m, INT2FIX(2));
+	  re = f_post_match(m);
+	  po = 1;
 	}
 	if (NIL_P(m)) {
+	    m = f_match(comp_pat1, s);
+	    if (!NIL_P(m)) {
+		sr = Qnil;
+		si = f_aref(m, INT2FIX(1));
+		if (NIL_P(si))
+		    si = rb_usascii_str_new2("");
+		{
+		    VALUE t;
+
+		    t = f_aref(m, INT2FIX(2));
+		    if (NIL_P(t))
+			t = rb_usascii_str_new2("1");
+		    rb_str_concat(si, t);
+		}
+		re = f_post_match(m);
+		po = 0;
+	    }
+	}
+	if (NIL_P(m)) {
 	    m = f_match(comp_pat2, s);
 	    if (NIL_P(m))
 		return rb_assoc_new(Qnil, self);
 	    sr = f_aref(m, INT2FIX(1));
-	    si = f_aref(m, INT2FIX(2));
+	    if (NIL_P(f_aref(m, INT2FIX(2))))
+		si = Qnil;
+	    else {
+		VALUE t;
+
+		si = f_aref(m, INT2FIX(3));
+		t = f_aref(m, INT2FIX(4));
+		if (NIL_P(t))
+		    t = rb_usascii_str_new2("1");
+		rb_str_concat(si, t);
+	    }
 	    re = f_post_match(m);
+	    po = 0;
 	}
 	r = INT2FIX(0);
 	i = INT2FIX(0);
@@ -1232,7 +1542,6 @@
 		r = f_to_i(sr);
 	}
 	if (!NIL_P(si)) {
-	    f_gsub_bang(si, image_garbages_pat, null_string);
 	    if (f_include_p(si, a_slash))
 		i = f_to_r(si);
 	    else if (f_gt_p(f_count(si, a_dot_and_an_e), INT2FIX(0)))
@@ -1240,7 +1549,10 @@
 	    else
 		i = f_to_i(si);
 	}
-	return rb_assoc_new(rb_complex_new2(r, i), re);
+	if (po)
+	    return rb_assoc_new(rb_complex_polar(r, i), re);
+	else
+	    return rb_assoc_new(rb_complex_new2(r, i), re);
     }
 }
 
@@ -1248,36 +1560,71 @@
 string_to_c_strict(VALUE self)
 {
     VALUE a = string_to_c_internal(self);
-    if (NIL_P(RARRAY_AT(a, 0)) || RSTRING_LEN(RARRAY_AT(a, 1)) > 0) {
+    if (NIL_P(RARRAY_PTR(a)[0]) || RSTRING_LEN(RARRAY_PTR(a)[1]) > 0) {
 	VALUE s = f_inspect(self);
-	rb_raise(rb_eArgError, "invalid value for Complex: %s",
+	rb_raise(rb_eArgError, "invalid value for convert(): %s",
 		 StringValuePtr(s));
     }
-    return RARRAY_AT(a, 0);
+    return RARRAY_PTR(a)[0];
 }
 
 #define id_gsub rb_intern("gsub")
 #define f_gsub(x,y,z) rb_funcall(x, id_gsub, 2, y, z)
 
+/*
+ * call-seq:
+ *    str.to_c  ->  complex
+ *
+ * Returns a complex which denotes the string form.  The parser
+ * ignores leading whitespaces and trailing garbage.  Any digit
+ * sequences can be separeted by an underscore.  Returns zero for null
+ * or garbage string.
+ *
+ * For example:
+ *
+ *    '9'.to_c           #=> (9+0i)
+ *    '2.5'.to_c         #=> (2.5+0i)
+ *    '2.5/1'.to_c       #=> ((5/2)+0i)
+ *    '-3/2'.to_c        #=> ((-3/2)+0i)
+ *    '-i'.to_c          #=> (0-1i)
+ *    '45i'.to_c         #=> (0+45i)
+ *    '3-4i'.to_c        #=> (3-4i)
+ *    '-4e2-4e-2i'.to_c  #=> (-400.0-0.04i)
+ *    '-0.0-0.0i'.to_c   #=> (-0.0-0.0i)
+ *    '1/2+3/4i'.to_c    #=> ((1/2)+(3/4)*i)
+ *    'ruby'.to_c        #=> (0+0i)
+ */
 static VALUE
-string_to_c(VALUE self)
+string_to_c(VALUE self, SEL sel)
 {
-    VALUE s = f_gsub(self, underscores_pat, an_underscore);
-    VALUE a = string_to_c_internal(s);
-    if (!NIL_P(RARRAY_AT(a, 0)))
-	return RARRAY_AT(a, 0);
+    VALUE s, a, backref;
+
+    backref = rb_backref_get();
+    rb_match_busy(backref);
+
+    s = f_gsub(self, underscores_pat, an_underscore);
+    a = string_to_c_internal(s);
+
+    rb_backref_set(backref);
+
+    if (!NIL_P(RARRAY_PTR(a)[0]))
+	return RARRAY_PTR(a)[0];
     return rb_complex_new1(INT2FIX(0));
 }
 
 static VALUE
-nucomp_s_convert(int argc, VALUE *argv, VALUE klass)
+nucomp_s_convert(VALUE klass, SEL sel, int argc, VALUE *argv)
 {
-    VALUE a1, a2;
+    VALUE a1, a2, backref;
 
-    a1 = Qnil;
-    a2 = Qnil;
-    rb_scan_args(argc, argv, "02", &a1, &a2);
+    rb_scan_args(argc, argv, "11", &a1, &a2);
 
+    if (NIL_P(a1) || (argc == 2 && NIL_P(a2)))
+	rb_raise(rb_eTypeError, "can't convert nil into Complex");
+
+    backref = rb_backref_get();
+    rb_match_busy(backref);
+
     switch (TYPE(a1)) {
       case T_FIXNUM:
       case T_BIGNUM:
@@ -1298,12 +1645,14 @@
 	break;
     }
 
+    rb_backref_set(backref);
+
     switch (TYPE(a1)) {
       case T_COMPLEX:
 	{
 	    get_dat1(a1);
 
-	    if (!k_float_p(dat->image) && f_zero_p(dat->image))
+	    if (k_exact_zero_p(dat->imag))
 		a1 = dat->real;
 	}
     }
@@ -1313,235 +1662,343 @@
 	{
 	    get_dat1(a2);
 
-	    if (!k_float_p(dat->image) && f_zero_p(dat->image))
+	    if (k_exact_zero_p(dat->imag))
 		a2 = dat->real;
 	}
     }
 
     switch (TYPE(a1)) {
       case T_COMPLEX:
-	if (NIL_P(a2) || f_zero_p(a2))
+	if (argc == 1 || (k_exact_zero_p(a2)))
 	    return a1;
     }
 
+    if (argc == 1) {
+	if (k_numeric_p(a1) && !f_real_p(a1))
+	    return a1;
+	/* expect raise exception for consistency */
+	if (!k_numeric_p(a1))
+	    return rb_convert_type(a1, T_COMPLEX, "Complex", "to_c");
+    }
+    else {
+	if ((k_numeric_p(a1) && k_numeric_p(a2)) &&
+	    (!f_real_p(a1) || !f_real_p(a2)))
+	    return f_add(a1,
+			 f_mul(a2,
+			       f_complex_new_bang2(rb_cComplex, ZERO, ONE)));
+    }
+
     {
 	VALUE argv2[2];
 	argv2[0] = a1;
 	argv2[1] = a2;
-	return nucomp_s_new(argc, argv2, klass);
+	return nucomp_s_new(klass, NULL, argc, argv2);
     }
 }
 
 /* --- */
 
-#define id_Complex rb_intern("Complex")
-
+/*
+ * call-seq:
+ *    num.real  ->  self
+ *
+ * Returns self.
+ */
 static VALUE
-numeric_re(VALUE self)
+numeric_real(VALUE self, SEL sel)
 {
-    return rb_Complex1(self);
+    return self;
 }
 
+/*
+ * call-seq:
+ *    num.imag       ->  0
+ *    num.imaginary  ->  0
+ *
+ * Returns zero.
+ */
 static VALUE
-numeric_im(VALUE self)
+numeric_imag(VALUE self, SEL sel)
 {
-    return rb_Complex2(ZERO, self);
+    return INT2FIX(0);
 }
 
+/*
+ * call-seq:
+ *    num.abs2  ->  real
+ *
+ * Returns square of self.
+ */
 static VALUE
-numeric_real(VALUE self)
+numeric_abs2(VALUE self, SEL sel)
 {
-    return self;
+    return f_mul(self, self);
 }
 
-static VALUE
-numeric_image(VALUE self)
-{
-    return INT2FIX(0);
-}
-
 #define id_PI rb_intern("PI")
 
+/*
+ * call-seq:
+ *    num.arg    ->  0 or float
+ *    num.angle  ->  0 or float
+ *    num.phase  ->  0 or float
+ *
+ * Returns 0 if the value is positive, pi otherwise.
+ */
 static VALUE
-numeric_arg(VALUE self)
+numeric_arg(VALUE self, SEL sel)
 {
-    if (!f_negative_p(self))
+    if (f_positive_p(self))
 	return INT2FIX(0);
     return rb_const_get(rb_mMath, id_PI);
 }
 
+/*
+ * call-seq:
+ *    num.rect  ->  array
+ *
+ * Returns an array; [num, 0].
+ */
 static VALUE
-numeric_polar(VALUE self)
+numeric_rect(VALUE self, SEL sel)
 {
+    return rb_assoc_new(self, INT2FIX(0));
+}
+
+/*
+ * call-seq:
+ *    num.polar  ->  array
+ *
+ * Returns an array; [num.abs, num.arg].
+ */
+static VALUE
+numeric_polar(VALUE self, SEL sel)
+{
     return rb_assoc_new(f_abs(self), f_arg(self));
 }
 
+/*
+ * call-seq:
+ *    num.conj       ->  self
+ *    num.conjucate  ->  self
+ *
+ * Returns self.
+ */
 static VALUE
-numeric_conjugate(VALUE self)
+numeric_conj(VALUE self, SEL sel)
 {
     return self;
 }
 
+/*
+ * call-seq:
+ *    flo.arg    ->  0 or float
+ *    flo.angle  ->  0 or float
+ *    flo.phase  ->  0 or float
+ *
+ * Returns 0 if the value is positive, pi otherwise.
+ */
+static VALUE
+float_arg(VALUE self, SEL sel)
+{
+    if (isnan(RFLOAT_VALUE(self)))
+	return self;
+    if (f_tpositive_p(self))
+	return INT2FIX(0);
+    return rb_const_get(rb_mMath, id_PI);
+}
+
+/*
+ * A complex number can be represented as a paired real number with
+ * imaginary unit; a+bi.  Where a is real part, b is imaginary part
+ * and i is imaginary unit.  Real a equals complex a+0i
+ * mathematically.
+ *
+ * In ruby, you can create complex object with Complex, Complex::rect,
+ * Complex::polar or to_c method.
+ *
+ *    Complex(1)           #=> (1+0i)
+ *    Complex(2, 3)        #=> (2+3i)
+ *    Complex.polar(2, 3)  #=> (-1.9799849932008908+0.2822400161197344i)
+ *    3.to_c               #=> (3+0i)
+ *
+ * You can also create complex object from floating-point numbers or
+ * strings.
+ *
+ *    Complex(0.3)         #=> (0.3+0i)
+ *    Complex('0.3-0.5i')  #=> (0.3-0.5i)
+ *    Complex('2/3+3/4i')  #=> ((2/3)+(3/4)*i)
+ *    Complex('1 at 2')       #=> (-0.4161468365471424+0.9092974268256817i)
+ *
+ *    0.3.to_c             #=> (0.3+0i)
+ *    '0.3-0.5i'.to_c      #=> (0.3-0.5i)
+ *    '2/3+3/4i'.to_c      #=> ((2/3)+(3/4)*i)
+ *    '1 at 2'.to_c           #=> (-0.4161468365471424+0.9092974268256817i)
+ *
+ * A complex object is either an exact or an inexact number.
+ *
+ *    Complex(1, 1) / 2    #=> ((1/2)+(1/2)*i)
+ *    Complex(1, 1) / 2.0  #=> (0.5+0.5i)
+ */
 void
 Init_Complex(void)
 {
     assert(fprintf(stderr, "assert() is now active\n"));
 
-    id_Unify = rb_intern("Unify");
     id_abs = rb_intern("abs");
     id_abs2 = rb_intern("abs2");
     id_arg = rb_intern("arg");
-    id_atan2_bang = rb_intern("atan2!");
     id_cmp = rb_intern("<=>");
-    id_conjugate = rb_intern("conjugate");
+    id_conj = rb_intern("conj");
     id_convert = rb_intern("convert");
-    id_cos = rb_intern("cos");
     id_denominator = rb_intern("denominator");
     id_divmod = rb_intern("divmod");
-    id_equal_p = rb_intern("==");
-    id_exact_p = rb_intern("exact?");
-    id_exp_bang = rb_intern("exp!");
+    id_eqeq_p = rb_intern("==");
     id_expt = rb_intern("**");
+    id_fdiv = rb_intern("fdiv");
     id_floor = rb_intern("floor");
-    id_format = rb_intern("format");
-    id_hypot = rb_intern("hypot");
     id_idiv = rb_intern("div");
+    id_imag = rb_intern("imag");
     id_inspect = rb_intern("inspect");
-    id_log_bang = rb_intern("log!");
     id_negate = rb_intern("-@");
-    id_new = rb_intern("new");
-    id_new_bang = rb_intern("new!");
     id_numerator = rb_intern("numerator");
-    id_polar = rb_intern("polar");
     id_quo = rb_intern("quo");
-    id_scalar_p = rb_intern("scalar?");
-    id_sin = rb_intern("sin");
-    id_sqrt = rb_intern("sqrt");
+    id_real = rb_intern("real");
+    id_real_p = rb_intern("real?");
     id_to_f = rb_intern("to_f");
     id_to_i = rb_intern("to_i");
     id_to_r = rb_intern("to_r");
     id_to_s = rb_intern("to_s");
-    id_truncate = rb_intern("truncate");
 
-    rb_cComplex = rb_define_class(COMPLEX_NAME, rb_cNumeric);
+    rb_cComplex = rb_define_class("Complex", rb_cNumeric);
 
-    rb_define_alloc_func(rb_cComplex, nucomp_s_alloc);
-//    rb_funcall(rb_cComplex, rb_intern("private_class_method"), 1,
-//	       ID2SYM(rb_intern("allocate")));
+    rb_objc_define_method(*(VALUE *)rb_cComplex, "alloc", nucomp_s_alloc, 0);
+    rb_undef_method(CLASS_OF(rb_cComplex), "allocate");
 
-    rb_define_singleton_method(rb_cComplex, "generic?", nucomp_s_generic_p, 1);
-
-    rb_define_singleton_method(rb_cComplex, "new!", nucomp_s_new_bang, -1);
-//    rb_funcall(rb_cComplex, rb_intern("private_class_method"), 1,
-//	       ID2SYM(rb_intern("new!")));
-
-    rb_define_singleton_method(rb_cComplex, "new", nucomp_s_new, -1);
-//    rb_funcall(rb_cComplex, rb_intern("private_class_method"), 1,
-//	       ID2SYM(rb_intern("new")));
-
 #if 0
-    rb_define_singleton_method(rb_cComplex, "rect", nucomp_s_new, -1);
-    rb_define_singleton_method(rb_cComplex, "rectangular", nucomp_s_new, -1);
+    rb_define_private_method(CLASS_OF(rb_cComplex), "new!", nucomp_s_new_bang, -1);
+    rb_define_private_method(CLASS_OF(rb_cComplex), "new", nucomp_s_new, -1);
+#else
+    rb_undef_method(CLASS_OF(rb_cComplex), "new");
 #endif
-    rb_define_singleton_method(rb_cComplex, "polar", nucomp_s_polar, 2);
 
-    rb_define_global_function(COMPLEX_NAME, nucomp_f_complex, -1);
+    rb_objc_define_method(*(VALUE *)rb_cComplex, "rectangular", nucomp_s_new, -1);
+    rb_objc_define_method(*(VALUE *)rb_cComplex, "rect", nucomp_s_new, -1);
+    rb_objc_define_method(*(VALUE *)rb_cComplex, "polar", nucomp_s_polar, -1);
 
+    rb_objc_define_method(rb_mKernel, "Complex", nucomp_f_complex, -1);
+
+    rb_undef_method(rb_cComplex, "%");
     rb_undef_method(rb_cComplex, "<");
     rb_undef_method(rb_cComplex, "<=");
     rb_undef_method(rb_cComplex, "<=>");
     rb_undef_method(rb_cComplex, ">");
     rb_undef_method(rb_cComplex, ">=");
     rb_undef_method(rb_cComplex, "between?");
+    rb_undef_method(rb_cComplex, "div");
     rb_undef_method(rb_cComplex, "divmod");
     rb_undef_method(rb_cComplex, "floor");
     rb_undef_method(rb_cComplex, "ceil");
     rb_undef_method(rb_cComplex, "modulo");
+    rb_undef_method(rb_cComplex, "remainder");
     rb_undef_method(rb_cComplex, "round");
     rb_undef_method(rb_cComplex, "step");
     rb_undef_method(rb_cComplex, "truncate");
 
-#if NUBY
+#if 0 /* NUBY */
     rb_undef_method(rb_cComplex, "//");
 #endif
 
-    rb_define_method(rb_cComplex, "real", nucomp_real, 0);
-    rb_define_method(rb_cComplex, "image", nucomp_image, 0);
-    rb_define_method(rb_cComplex, "imag", nucomp_image, 0);
+    rb_objc_define_method(rb_cComplex, "real", nucomp_real, 0);
+    rb_objc_define_method(rb_cComplex, "imaginary", nucomp_imag, 0);
+    rb_objc_define_method(rb_cComplex, "imag", nucomp_imag, 0);
 
-    rb_define_method(rb_cComplex, "+", nucomp_add, 1);
-    rb_define_method(rb_cComplex, "-", nucomp_sub, 1);
-    rb_define_method(rb_cComplex, "*", nucomp_mul, 1);
-    rb_define_method(rb_cComplex, "/", nucomp_div, 1);
-    rb_define_method(rb_cComplex, "quo", nucomp_quo, 1);
-    rb_define_method(rb_cComplex, "fdiv", nucomp_fdiv, 1);
-    rb_define_method(rb_cComplex, "**", nucomp_expt, 1);
+    rb_objc_define_method(rb_cComplex, "-@", nucomp_negate, 0);
+    rb_objc_define_method(rb_cComplex, "+", nucomp_add, 1);
+    rb_objc_define_method(rb_cComplex, "-", nucomp_sub, 1);
+    rb_objc_define_method(rb_cComplex, "*", nucomp_mul, 1);
+    rb_objc_define_method(rb_cComplex, "/", nucomp_div, 1);
+    rb_objc_define_method(rb_cComplex, "quo", nucomp_quo, 1);
+    rb_objc_define_method(rb_cComplex, "fdiv", nucomp_fdiv, 1);
+    rb_objc_define_method(rb_cComplex, "**", nucomp_expt, 1);
 
-    rb_define_method(rb_cComplex, "==", nucomp_equal_p, 1);
-    rb_define_method(rb_cComplex, "coerce", nucomp_coerce, 1);
+    rb_objc_define_method(rb_cComplex, "==", nucomp_eqeq_p, 1);
+    rb_objc_define_method(rb_cComplex, "coerce", nucomp_coerce, 1);
 
-    rb_define_method(rb_cComplex, "abs", nucomp_abs, 0);
+    rb_objc_define_method(rb_cComplex, "abs", nucomp_abs, 0);
+    rb_objc_define_method(rb_cComplex, "magnitude", nucomp_abs, 0);
+    rb_objc_define_method(rb_cComplex, "abs2", nucomp_abs2, 0);
+    rb_objc_define_method(rb_cComplex, "arg", nucomp_arg, 0);
+    rb_objc_define_method(rb_cComplex, "angle", nucomp_arg, 0);
+    rb_objc_define_method(rb_cComplex, "phase", nucomp_arg, 0);
+    rb_objc_define_method(rb_cComplex, "rectangular", nucomp_rect, 0);
+    rb_objc_define_method(rb_cComplex, "rect", nucomp_rect, 0);
+    rb_objc_define_method(rb_cComplex, "polar", nucomp_polar, 0);
+    rb_objc_define_method(rb_cComplex, "conjugate", nucomp_conj, 0);
+    rb_objc_define_method(rb_cComplex, "conj", nucomp_conj, 0);
 #if 0
-    rb_define_method(rb_cComplex, "magnitude", nucomp_abs, 0);
+    rb_define_method(rb_cComplex, "~", nucomp_conj, 0); /* gcc */
 #endif
-    rb_define_method(rb_cComplex, "abs2", nucomp_abs2, 0);
-    rb_define_method(rb_cComplex, "arg", nucomp_arg, 0);
-    rb_define_method(rb_cComplex, "angle", nucomp_arg, 0);
-    rb_define_method(rb_cComplex, "polar", nucomp_polar, 0);
-    rb_define_method(rb_cComplex, "conjugate", nucomp_conjugate, 0);
-    rb_define_method(rb_cComplex, "conj", nucomp_conjugate, 0);
-#if 0
-    rb_define_method(rb_cComplex, "~", nucomp_conjugate, 0); /* gcc */
-#endif
 
+    rb_objc_define_method(rb_cComplex, "real?", nucomp_false, 0);
 #if 0
-    rb_define_method(rb_cComplex, "real?", nucomp_real_p, 0);
-    rb_define_method(rb_cComplex, "complex?", nucomp_complex_p, 0);
+    rb_define_method(rb_cComplex, "complex?", nucomp_true, 0);
     rb_define_method(rb_cComplex, "exact?", nucomp_exact_p, 0);
     rb_define_method(rb_cComplex, "inexact?", nucomp_inexact_p, 0);
 #endif
 
-    rb_define_method(rb_cComplex, "numerator", nucomp_numerator, 0);
-    rb_define_method(rb_cComplex, "denominator", nucomp_denominator, 0);
+    rb_objc_define_method(rb_cComplex, "numerator", nucomp_numerator, 0);
+    rb_objc_define_method(rb_cComplex, "denominator", nucomp_denominator, 0);
 
-    rb_define_method(rb_cComplex, "hash", nucomp_hash, 0);
+    rb_objc_define_method(rb_cComplex, "hash", nucomp_hash, 0);
+    rb_objc_define_method(rb_cComplex, "eql?", nucomp_eql_p, 1);
 
-    rb_define_method(rb_cComplex, "to_s", nucomp_to_s, 0);
-    rb_define_method(rb_cComplex, "inspect", nucomp_inspect, 0);
+    rb_objc_define_method(rb_cComplex, "to_s", nucomp_to_s, 0);
+    rb_objc_define_method(rb_cComplex, "inspect", nucomp_inspect, 0);
 
-    rb_define_method(rb_cComplex, "marshal_dump", nucomp_marshal_dump, 0);
-    rb_define_method(rb_cComplex, "marshal_load", nucomp_marshal_load, 1);
+    rb_objc_define_method(rb_cComplex, "marshal_dump", nucomp_marshal_dump, 0);
+    rb_objc_define_method(rb_cComplex, "marshal_load", nucomp_marshal_load, 1);
 
-    /* --- */
+    /* objc_--- */
 
-    rb_define_method(rb_cComplex, "scalar?", nucomp_scalar_p, 0);
-    rb_define_method(rb_cComplex, "to_i", nucomp_to_i, 0);
-    rb_define_method(rb_cComplex, "to_f", nucomp_to_f, 0);
-    rb_define_method(rb_cComplex, "to_r", nucomp_to_r, 0);
-    rb_define_method(rb_cNilClass, "to_c", nilclass_to_c, 0);
-    rb_define_method(rb_cNumeric, "to_c", numeric_to_c, 0);
+    rb_objc_define_method(rb_cComplex, "to_i", nucomp_to_i, 0);
+    rb_objc_define_method(rb_cComplex, "to_f", nucomp_to_f, 0);
+    rb_objc_define_method(rb_cComplex, "to_r", nucomp_to_r, 0);
+    rb_objc_define_method(rb_cNilClass, "to_c", nilclass_to_c, 0);
+    rb_objc_define_method(rb_cNumeric, "to_c", numeric_to_c, 0);
 
     make_patterns();
 
-    rb_define_method(rb_cString, "to_c", string_to_c, 0);
+    rb_objc_define_method(rb_cString, "to_c", string_to_c, 0);
 
-    rb_define_singleton_method(rb_cComplex, "convert", nucomp_s_convert, -1);
-//    rb_funcall(rb_cComplex, rb_intern("private_class_method"), 1,
-//	       ID2SYM(rb_intern("convert")));
+    rb_objc_define_method(*(VALUE *)rb_cComplex, "convert", nucomp_s_convert, -1);
+//    rb_define_private_method(CLASS_OF(rb_cComplex), "convert", nucomp_s_convert, -1);
 
     /* --- */
 
-    rb_define_method(rb_cNumeric, "re", numeric_re, 0);
-    rb_define_method(rb_cNumeric, "im", numeric_im, 0);
-    rb_define_method(rb_cNumeric, "real", numeric_real, 0);
-    rb_define_method(rb_cNumeric, "image", numeric_image, 0);
-    rb_define_method(rb_cNumeric, "imag", numeric_image, 0);
-    rb_define_method(rb_cNumeric, "arg", numeric_arg, 0);
-    rb_define_method(rb_cNumeric, "angle", numeric_arg, 0);
-    rb_define_method(rb_cNumeric, "polar", numeric_polar, 0);
-    rb_define_method(rb_cNumeric, "conjugate", numeric_conjugate, 0);
-    rb_define_method(rb_cNumeric, "conj", numeric_conjugate, 0);
+    rb_objc_define_method(rb_cNumeric, "real", numeric_real, 0);
+    rb_objc_define_method(rb_cNumeric, "imaginary", numeric_imag, 0);
+    rb_objc_define_method(rb_cNumeric, "imag", numeric_imag, 0);
+    rb_objc_define_method(rb_cNumeric, "abs2", numeric_abs2, 0);
+    rb_objc_define_method(rb_cNumeric, "arg", numeric_arg, 0);
+    rb_objc_define_method(rb_cNumeric, "angle", numeric_arg, 0);
+    rb_objc_define_method(rb_cNumeric, "phase", numeric_arg, 0);
+    rb_objc_define_method(rb_cNumeric, "rectangular", numeric_rect, 0);
+    rb_objc_define_method(rb_cNumeric, "rect", numeric_rect, 0);
+    rb_objc_define_method(rb_cNumeric, "polar", numeric_polar, 0);
+    rb_objc_define_method(rb_cNumeric, "conjugate", numeric_conj, 0);
+    rb_objc_define_method(rb_cNumeric, "conj", numeric_conj, 0);
 
+    rb_objc_define_method(rb_cFloat, "arg", float_arg, 0);
+    rb_objc_define_method(rb_cFloat, "angle", float_arg, 0);
+    rb_objc_define_method(rb_cFloat, "phase", float_arg, 0);
+
     rb_define_const(rb_cComplex, "I",
 		    f_complex_new_bang2(rb_cComplex, ZERO, ONE));
 }
+
+/*
+Local variables:
+c-file-style: "ruby"
+End:
+*/

Modified: MacRuby/branches/experimental/include/ruby/ruby.h
===================================================================
--- MacRuby/branches/experimental/include/ruby/ruby.h	2009-07-29 19:32:58 UTC (rev 2116)
+++ MacRuby/branches/experimental/include/ruby/ruby.h	2009-07-30 05:04:52 UTC (rev 2117)
@@ -669,7 +669,7 @@
 struct RComplex {
     struct RBasic basic;
     VALUE real;
-    VALUE image;
+    VALUE imag;
 };
 
 struct RData {

Modified: MacRuby/branches/experimental/numeric.c
===================================================================
--- MacRuby/branches/experimental/numeric.c	2009-07-29 19:32:58 UTC (rev 2116)
+++ MacRuby/branches/experimental/numeric.c	2009-07-30 05:04:52 UTC (rev 2117)
@@ -405,7 +405,9 @@
 static VALUE
 num_modulo(VALUE x, SEL sel, VALUE y)
 {
-    return rb_funcall(x, '%', 1, y);
+      return rb_funcall(x, '-', 1,
+              rb_funcall(y, '*', 1,
+              rb_funcall(x, rb_intern("div"), 1, y)));
 }
 
 /*
@@ -437,6 +439,20 @@
 
 /*
  *  call-seq:
+ *     num.real?  ->  true or false
+ *
+ *  Returns <code>true</code> if <i>num</i> is a <code>Real</code>
+ *  (i.e. non <code>Complex</code>).
+ */
+
+static VALUE
+num_real_p(VALUE num, SEL sel)
+{
+    return Qtrue;
+}
+
+/*
+ *  call-seq:
  *     num.scalar? -> true or false
  *
  *  Returns <code>true</code> if <i>num</i> is an <code>Scalar</code>
@@ -3267,11 +3283,13 @@
     rb_objc_define_method(rb_cNumeric, "fdiv", num_fdiv, 1);
     rb_objc_define_method(rb_cNumeric, "div", num_div, 1);
     rb_objc_define_method(rb_cNumeric, "divmod", num_divmod, 1);
+    rb_objc_define_method(rb_cNumeric, "%", num_modulo, 1);
     rb_objc_define_method(rb_cNumeric, "modulo", num_modulo, 1);
     rb_objc_define_method(rb_cNumeric, "remainder", num_remainder, 1);
     rb_objc_define_method(rb_cNumeric, "abs", num_abs, 0);
     rb_objc_define_method(rb_cNumeric, "to_int", num_to_int, 0);
-
+    
+    rb_objc_define_method(rb_cNumeric, "real?", num_real_p, 0);
     rb_objc_define_method(rb_cNumeric, "scalar?", num_scalar_p, 0);
     rb_objc_define_method(rb_cNumeric, "integer?", num_int_p, 0);
     rb_objc_define_method(rb_cNumeric, "zero?", num_zero_p, 0);

Modified: MacRuby/branches/experimental/rational.c
===================================================================
--- MacRuby/branches/experimental/rational.c	2009-07-29 19:32:58 UTC (rev 2116)
+++ MacRuby/branches/experimental/rational.c	2009-07-30 05:04:52 UTC (rev 2117)
@@ -1,5 +1,5 @@
 /*
-  rational.c: Coded by Tadayoshi Funaba 2008
+  rational.c: Coded by Tadayoshi Funaba 2008,2009
 
   This implementation is based on Keiju Ishitsuka's Rational library
   which is written in ruby.
@@ -8,23 +8,24 @@
 #include "ruby.h"
 #include <math.h>
 #include <float.h>
+#include "ruby/re.h"
 
+#ifdef HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
+
 #define NDEBUG
 #include <assert.h>
 
-#ifndef RATIONAL_NAME
-#define RATIONAL_NAME "Rational"
-#endif
-
 #define ZERO INT2FIX(0)
 #define ONE INT2FIX(1)
 #define TWO INT2FIX(2)
 
 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_negate, id_new,
-  id_new_bang, id_to_f, id_to_i, id_to_s, id_truncate;
+static ID id_abs, id_cmp, id_convert, id_eqeq_p, id_expt, id_fdiv,
+    id_floor, 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)
 
@@ -52,72 +53,49 @@
 inline static VALUE
 f_add(VALUE x, VALUE y)
 {
-    VALUE r;
-    if (FIXNUM_P(y)) {
-	if (FIX2LONG(y) == 0)
-	    r = x;
-	else
-	    r = rb_funcall(x, '+', 1, y);
-    }
-    else if (FIXNUM_P(x)) {
-	if (FIX2LONG(x) == 0)
-	    r = y;
-	else
-	    r = rb_funcall(x, '+', 1, y);
-    }
-    else
-	r = rb_funcall(x, '+', 1, y);
-    return r;
+    if (FIXNUM_P(y) && FIX2LONG(y) == 0)
+	return x;
+    else if (FIXNUM_P(x) && FIX2LONG(x) == 0)
+	return y;
+    return rb_funcall(x, '+', 1, y);
 }
 
 inline static VALUE
 f_cmp(VALUE x, VALUE y)
 {
-    VALUE r;
     if (FIXNUM_P(x) && FIXNUM_P(y)) {
 	long c = FIX2LONG(x) - FIX2LONG(y);
 	if (c > 0)
 	    c = 1;
 	else if (c < 0)
 	    c = -1;
-	r = INT2FIX(c);
+	return INT2FIX(c);
     }
-    else
-	r = rb_funcall(x, id_cmp, 1, y);
-    return r;
+    return rb_funcall(x, id_cmp, 1, y);
 }
 
 inline static VALUE
 f_div(VALUE x, VALUE y)
 {
-    VALUE r;
     if (FIXNUM_P(y) && FIX2LONG(y) == 1)
-	r = x;
-    else
-	r = rb_funcall(x, '/', 1, y);
-    return r;
+	return x;
+    return rb_funcall(x, '/', 1, y);
 }
 
 inline static VALUE
 f_gt_p(VALUE x, VALUE y)
 {
-    VALUE r;
     if (FIXNUM_P(x) && FIXNUM_P(y))
-	r = f_boolcast(FIX2LONG(x) > FIX2LONG(y));
-    else
-	r = rb_funcall(x, '>', 1, y);
-    return r;
+	return f_boolcast(FIX2LONG(x) > FIX2LONG(y));
+    return rb_funcall(x, '>', 1, y);
 }
 
 inline static VALUE
 f_lt_p(VALUE x, VALUE y)
 {
-    VALUE r;
     if (FIXNUM_P(x) && FIXNUM_P(y))
-	r = f_boolcast(FIX2LONG(x) < FIX2LONG(y));
-    else
-	r = rb_funcall(x, '<', 1, y);
-    return r;
+	return f_boolcast(FIX2LONG(x) < FIX2LONG(y));
+    return rb_funcall(x, '<', 1, y);
 }
 
 binop(mod, '%')
@@ -125,58 +103,39 @@
 inline static VALUE
 f_mul(VALUE x, VALUE y)
 {
-    VALUE r;
     if (FIXNUM_P(y)) {
-	long _iy = FIX2LONG(y);
-	if (_iy == 0) {
-	    if (TYPE(x) == T_FLOAT)
-		r = rb_float_new(0.0);
-	    else
-		r = ZERO;
+	long iy = FIX2LONG(y);
+	if (iy == 0) {
+	    if (FIXNUM_P(x) || TYPE(x) == T_BIGNUM)
+		return ZERO;
 	}
-	else if (_iy == 1)
-	    r = x;
-	else
-	    r = rb_funcall(x, '*', 1, y);
+	else if (iy == 1)
+	    return x;
     }
     else if (FIXNUM_P(x)) {
-	long _ix = FIX2LONG(x);
-	if (_ix == 0) {
-	    if (TYPE(y) == T_FLOAT)
-		r = rb_float_new(0.0);
-	    else
-		r = ZERO;
+	long ix = FIX2LONG(x);
+	if (ix == 0) {
+	    if (FIXNUM_P(y) || TYPE(y) == T_BIGNUM)
+		return ZERO;
 	}
-	else if (_ix == 1)
-	    r = y;
-	else
-	    r = rb_funcall(x, '*', 1, y);
+	else if (ix == 1)
+	    return y;
     }
-    else
-	r = rb_funcall(x, '*', 1, y);
-    return r;
+    return rb_funcall(x, '*', 1, y);
 }
 
 inline static VALUE
 f_sub(VALUE x, VALUE y)
 {
-    VALUE r;
-    if (FIXNUM_P(y)) {
-	if (FIX2LONG(y) == 0)
-	    r = x;
-	else
-	    r = rb_funcall(x, '-', 1, y);
-    }
-    else
-	r = rb_funcall(x, '-', 1, y);
-    return r;
+    if (FIXNUM_P(y) && FIX2LONG(y) == 0)
+	return x;
+    return rb_funcall(x, '-', 1, y);
 }
 
-binop(xor, '^')
-
 fun1(abs)
 fun1(floor)
 fun1(inspect)
+fun1(integer_p)
 fun1(negate)
 fun1(to_f)
 fun1(to_i)
@@ -184,50 +143,65 @@
 fun1(truncate)
 
 inline static VALUE
-f_equal_p(VALUE x, VALUE y)
+f_eqeq_p(VALUE x, VALUE y)
 {
-    VALUE r;
     if (FIXNUM_P(x) && FIXNUM_P(y))
-	r = f_boolcast(FIX2LONG(x) == FIX2LONG(y));
-    else
-	r = rb_funcall(x, id_equal_p, 1, y);
-    return r;
+	return f_boolcast(FIX2LONG(x) == FIX2LONG(y));
+    return rb_funcall(x, id_eqeq_p, 1, y);
 }
 
 fun2(expt)
+fun2(fdiv)
 fun2(idiv)
 
 inline static VALUE
 f_negative_p(VALUE x)
 {
-    VALUE r;
     if (FIXNUM_P(x))
-	r = f_boolcast(FIX2LONG(x) < 0);
-    else
-	r = rb_funcall(x, '<', 1, ZERO);
-    return r;
+	return f_boolcast(FIX2LONG(x) < 0);
+    return rb_funcall(x, '<', 1, ZERO);
 }
 
+#define f_positive_p(x) (!f_negative_p(x))
+
 inline static VALUE
 f_zero_p(VALUE x)
 {
-    VALUE r;
-    if (FIXNUM_P(x))
-	r = f_boolcast(FIX2LONG(x) == 0);
-    else
-	r = rb_funcall(x, id_equal_p, 1, ZERO);
-    return r;
+    switch (TYPE(x)) {
+      case T_FIXNUM:
+	return f_boolcast(FIX2LONG(x) == 0);
+      case T_BIGNUM:
+	return Qfalse;
+      case T_RATIONAL:
+      {
+	  VALUE num = RRATIONAL(x)->num;
+
+	  return f_boolcast(FIXNUM_P(num) && FIX2LONG(num) == 0);
+      }
+    }
+    return rb_funcall(x, id_eqeq_p, 1, ZERO);
 }
 
+#define f_nonzero_p(x) (!f_zero_p(x))
+
 inline static VALUE
 f_one_p(VALUE x)
 {
-    VALUE r;
-    if (FIXNUM_P(x))
-	r = f_boolcast(FIX2LONG(x) == 1);
-    else
-	r = rb_funcall(x, id_equal_p, 1, ONE);
-    return r;
+    switch (TYPE(x)) {
+      case T_FIXNUM:
+	return f_boolcast(FIX2LONG(x) == 1);
+      case T_BIGNUM:
+	return Qfalse;
+      case T_RATIONAL:
+      {
+	  VALUE num = RRATIONAL(x)->num;
+	  VALUE den = RRATIONAL(x)->den;
+
+	  return f_boolcast(FIXNUM_P(num) && FIX2LONG(num) == 1 &&
+			    FIXNUM_P(den) && FIX2LONG(den) == 1);
+      }
+    }
+    return rb_funcall(x, id_eqeq_p, 1, ONE);
 }
 
 inline static VALUE
@@ -260,6 +234,12 @@
     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)
+
+#define k_exact_zero_p(x) (k_exact_p(x) && f_zero_p(x))
+#define k_exact_one_p(x) (k_exact_p(x) && f_one_p(x))
+
 #ifndef NDEBUG
 #define f_gcd f_gcd_orig
 #endif
@@ -267,8 +247,6 @@
 inline static long
 i_gcd(long x, long y)
 {
-    long b;
-
     if (x < 0)
 	x = -x;
     if (y < 0)
@@ -279,32 +257,12 @@
     if (y == 0)
 	return x;
 
-    b = 0;
-    while ((x & 1) == 0 && (y & 1) == 0) {
-	b += 1;
-	x >>= 1;
-	y >>= 1;
+    while (x > 0) {
+	long t = x;
+	x = y % x;
+	y = t;
     }
-
-    while ((x & 1) == 0)
-	x >>= 1;
-
-    while ((y & 1) == 0)
-	y >>= 1;
-
-    while (x != y) {
-	if (y > x) {
-	    long t;
-	    t = x;
-	    x = y;
-	    y = t;
-	}
-	x -= y;
-	while ((x & 1) == 0)
-	    x >>= 1;
-    }
-
-    return x << b;
+    return y;
 }
 
 inline static VALUE
@@ -346,7 +304,7 @@
 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)));
     }
@@ -359,8 +317,7 @@
 {
     if (f_zero_p(x) || f_zero_p(y))
 	return ZERO;
-    else
-	return f_abs(f_mul(f_div(x, f_gcd(x, y)), y));
+    return f_abs(f_mul(f_div(x, f_gcd(x, y)), y));
 }
 
 #define get_dat1(x) \
@@ -385,11 +342,14 @@
 }
 
 static VALUE
-nurat_s_alloc(VALUE klass)
+nurat_s_alloc(VALUE klass, SEL sel)
 {
     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)
 {
@@ -413,7 +373,7 @@
 	    den = f_negate(den);
 	    break;
 	  case 0:
-	    rb_raise(rb_eZeroDivError, "devided by zero");
+	    rb_raise_zerodiv();
 	    break;
 	}
 	break;
@@ -421,6 +381,7 @@
 
     return nurat_s_new_internal(klass, num, den);
 }
+#endif
 
 inline static VALUE
 f_rational_new_bang1(VALUE klass, VALUE x)
@@ -431,13 +392,25 @@
 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);
 }
 
-#define f_unify_p(klass) rb_const_defined(klass, id_Unify)
+#ifdef CANONICALIZATION_FOR_MATHN
+#define CANON
+#endif
 
+#ifdef CANON
+static int canonicalization = 0;
+
+void
+nurat_canonicalization(int f)
+{
+    canonicalization = f;
+}
+#endif
+
 inline static void
 nurat_int_check(VALUE num)
 {
@@ -446,11 +419,21 @@
       case T_BIGNUM:
 	break;
       default:
-	rb_raise(rb_eArgError, "not an integer");
+	if (!k_numeric_p(num) || !f_integer_p(num))
+	    rb_raise(rb_eArgError, "not an integer");
     }
 }
 
 inline static VALUE
+nurat_int_value(VALUE num)
+{
+    nurat_int_check(num);
+    if (!k_integer_p(num))
+	num = f_to_i(num);
+    return num;
+}
+
+inline static VALUE
 nurat_s_canonicalize_internal(VALUE klass, VALUE num, VALUE den)
 {
     VALUE gcd;
@@ -461,7 +444,7 @@
 	den = f_negate(den);
 	break;
       case 0:
-	rb_raise(rb_eZeroDivError, "devided by zero");
+	rb_raise_zerodiv();
 	break;
     }
 
@@ -469,10 +452,11 @@
     num = f_idiv(num, gcd);
     den = f_idiv(den, gcd);
 
-    if (f_one_p(den) && f_unify_p(klass))
+#ifdef CANON
+    if (f_one_p(den) && canonicalization)
 	return num;
-    else
-	return nurat_s_new_internal(klass, num, den);
+#endif
+    return nurat_s_new_internal(klass, num, den);
 }
 
 inline static VALUE
@@ -484,53 +468,36 @@
 	den = f_negate(den);
 	break;
       case 0:
-	rb_raise(rb_eZeroDivError, "devided by zero");
+	rb_raise_zerodiv();
 	break;
     }
 
-    if (f_equal_p(den, ONE) && f_unify_p(klass))
+#ifdef CANON
+    if (f_one_p(den) && canonicalization)
 	return num;
-    else
-	return nurat_s_new_internal(klass, num, den);
+#endif
+    return nurat_s_new_internal(klass, num, den);
 }
 
-#if 0
 static VALUE
-nurat_s_canonicalize(int argc, VALUE *argv, VALUE klass)
+nurat_s_new(int argc, VALUE *argv, VALUE klass)
 {
     VALUE num, den;
 
-    if (rb_scan_args(argc, argv, "11", &num, &den) == 1) {
+    switch (rb_scan_args(argc, argv, "11", &num, &den)) {
+      case 1:
+	num = nurat_int_value(num);
 	den = ONE;
+	break;
+      default:
+	num = nurat_int_value(num);
+	den = nurat_int_value(den);
+	break;
     }
 
-    nurat_int_check(num);
-    nurat_int_check(den);
-
     return nurat_s_canonicalize_internal(klass, num, den);
 }
-#endif
 
-static VALUE
-nurat_s_new(VALUE klass, VALUE num, VALUE den)
-{
-    nurat_int_check(num);
-    nurat_int_check(den);
-
-    return nurat_s_canonicalize_internal(klass, num, den);
-}
-
-static VALUE
-nurat_s_new_m(int argc, VALUE *argv, VALUE klass)
-{
-    VALUE num, den;
-
-    if (rb_scan_args(argc, argv, "11", &num, &den) == 1) {
-	den = ONE;
-    }
-    return nurat_s_new(klass, num, den);
-}
-
 inline static VALUE
 f_rational_new1(VALUE klass, VALUE x)
 {
@@ -561,21 +528,54 @@
     return nurat_s_canonicalize_internal_no_reduce(klass, x, y);
 }
 
+/*
+ * call-seq:
+ *    Rational(x[, y])  ->  numeric
+ *
+ * Returns x/y;
+ */
 static VALUE
-nurat_f_rational(int argc, VALUE *argv, VALUE klass)
+nurat_f_rational(VALUE klass, SEL sel, int argc, VALUE *argv)
 {
     return rb_funcall2(rb_cRational, id_convert, argc, argv);
 }
 
+/*
+ * call-seq:
+ *    rat.numerator  ->  integer
+ *
+ * Returns the numerator.
+ *
+ * For example:
+ *
+ *    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)
+nurat_numerator(VALUE self, SEL sel)
 {
     get_dat1(self);
     return dat->num;
 }
 
+/*
+ * call-seq:
+ *    rat.denominator  ->  integer
+ *
+ * Returns the denominator (always positive).
+ *
+ * For example:
+ *
+ *    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)
+nurat_denominator(VALUE self, SEL sel)
 {
     get_dat1(self);
     return dat->den;
@@ -612,7 +612,7 @@
 f_imul(long x, long y)
 {
     VALUE r = f_imul_orig(x, y);
-    assert(f_equal_p(r, f_mul(LONG2NUM(x), LONG2NUM(y))));
+    assert(f_eqeq_p(r, f_mul(LONG2NUM(x), LONG2NUM(y))));
     return r;
 }
 #endif
@@ -666,8 +666,22 @@
     return f_rational_new_no_reduce2(CLASS_OF(self), num, den);
 }
 
+/*
+ * call-seq:
+ *    rat + numeric  ->  numeric_result
+ *
+ * Performs addition.
+ *
+ * For example:
+ *
+ *    Rational(2, 3)  + Rational(2, 3)   #=> (4/3)
+ *    Rational(900)   + Rational(1)      #=> (900/1)
+ *    Rational(-2, 9) + Rational(-9, 2)  #=> (-85/18)
+ *    Rational(9, 8)  + 4                #=> (41/8)
+ *    Rational(20, 9) + 9.8              #=> 12.022222222222222
+ */
 static VALUE
-nurat_add(VALUE self, VALUE other)
+nurat_add(VALUE self, SEL sel, VALUE other)
 {
     switch (TYPE(other)) {
       case T_FIXNUM:
@@ -694,8 +708,22 @@
     }
 }
 
+/*
+ * call-seq:
+ *    rat - numeric  ->  numeric_result
+ *
+ * Performs subtraction.
+ *
+ * For example:
+ *
+ *    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)
+nurat_sub(VALUE self, SEL sel, VALUE other)
 {
     switch (TYPE(other)) {
       case T_FIXNUM:
@@ -761,8 +789,22 @@
     return f_rational_new_no_reduce2(CLASS_OF(self), num, den);
 }
 
+/*
+ * call-seq:
+ *    rat * numeric  ->  numeric_result
+ *
+ * Performs multiplication.
+ *
+ * For example:
+ *
+ *    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)
+nurat_mul(VALUE self, SEL sel, VALUE other)
 {
     switch (TYPE(other)) {
       case T_FIXNUM:
@@ -789,14 +831,29 @@
     }
 }
 
+/*
+ * call-seq:
+ *    rat / numeric     ->  numeric_result
+ *    rat.quo(numeric)  ->  numeric_result
+ *
+ * Performs division.
+ *
+ * For example:
+ *
+ *    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)
+nurat_div(VALUE self, SEL sel, VALUE other)
 {
     switch (TYPE(other)) {
       case T_FIXNUM:
       case T_BIGNUM:
 	if (f_zero_p(other))
-	    rb_raise(rb_eZeroDivError, "devided by zero");
+	    rb_raise_zerodiv();
 	{
 	    get_dat1(self);
 
@@ -808,10 +865,14 @@
 	return rb_funcall(f_to_f(self), '/', 1, other);
       case T_RATIONAL:
 	if (f_zero_p(other))
-	    rb_raise(rb_eZeroDivError, "devided by zero");
+	    rb_raise_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, '/');
@@ -821,28 +882,58 @@
     }
 }
 
+/*
+ * call-seq:
+ *    rat.fdiv(numeric)  ->  float
+ *
+ * Performs division and returns the value as a float.
+ *
+ * For example:
+ *
+ *    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)
+nurat_fdiv(VALUE self, SEL sel, VALUE other)
 {
-    return f_div(f_to_f(self), other);
+    if (f_zero_p(other))
+	return f_div(self, f_to_f(other));
+    return f_to_f(f_div(self, other));
 }
 
+extern VALUE rb_fexpt(VALUE x, VALUE y);
+
+/*
+ * call-seq:
+ *    rat ** numeric  ->  numeric_result
+ *
+ * Performs exponentiation.
+ *
+ * For example:
+ *
+ *    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)
+nurat_expt(VALUE self, SEL sel, VALUE other)
 {
-    if (f_zero_p(other))
+    if (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; /* good? */
+	    other = dat->num; /* c14n */
     }
 
     switch (TYPE(other)) {
       case T_FIXNUM:
-      case T_BIGNUM:
 	{
 	    VALUE num, den;
 
@@ -864,6 +955,9 @@
 	    }
 	    return f_rational_new2(CLASS_OF(self), num, den);
 	}
+      case T_BIGNUM:
+	rb_warn("in a**b, b may be too big");
+	/* fall through */
       case T_FLOAT:
       case T_RATIONAL:
 	return f_expt(f_to_f(self), other);
@@ -872,8 +966,22 @@
     }
 }
 
+/*
+ * call-seq:
+ *    rat <=> numeric  ->  -1, 0, +1 or nil
+ *
+ * Performs comparison and returns -1, 0, or +1.
+ *
+ * For example:
+ *
+ *    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
+ */
 static VALUE
-nurat_cmp(VALUE self, VALUE other)
+nurat_cmp(VALUE self, SEL sel, VALUE other)
 {
     switch (TYPE(other)) {
       case T_FIXNUM:
@@ -882,9 +990,8 @@
 	    get_dat1(self);
 
 	    if (FIXNUM_P(dat->den) && FIX2LONG(dat->den) == 1)
-		return f_cmp(dat->num, other);
-	    else
-		return f_cmp(self, f_rational_new_bang1(CLASS_OF(self), other));
+		return f_cmp(dat->num, other); /* c14n */
+	    return f_cmp(self, f_rational_new_bang1(CLASS_OF(self), other));
 	}
       case T_FLOAT:
 	return f_cmp(f_to_f(self), other);
@@ -906,12 +1013,26 @@
 	    return f_cmp(f_sub(num1, num2), ZERO);
 	}
       default:
-	return rb_num_coerce_bin(self, other, id_cmp);
+	return rb_num_coerce_cmp(self, other, id_cmp);
     }
 }
 
+/*
+ * call-seq:
+ *    rat == object  ->  true or false
+ *
+ * Returns true if rat equals object numerically.
+ *
+ * For example:
+ *
+ *    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_equal_p(VALUE self, VALUE other)
+nurat_eqeq_p(VALUE self, SEL sel, VALUE other)
 {
     switch (TYPE(other)) {
       case T_FIXNUM:
@@ -919,31 +1040,37 @@
 	{
 	    get_dat1(self);
 
+	    if (f_zero_p(dat->num) && f_zero_p(other))
+		return Qtrue;
+
 	    if (!FIXNUM_P(dat->den))
 		return Qfalse;
 	    if (FIX2LONG(dat->den) != 1)
 		return Qfalse;
-	    if (f_equal_p(dat->num, other))
+	    if (f_eqeq_p(dat->num, other))
 		return Qtrue;
-	    else
-		return Qfalse;
+	    return Qfalse;
 	}
       case T_FLOAT:
-	return f_equal_p(f_to_f(self), other);
+	return f_eqeq_p(f_to_f(self), other);
       case T_RATIONAL:
 	{
 	    get_dat2(self, other);
 
-	    return f_boolcast(f_equal_p(adat->num, bdat->num) &&
-			      f_equal_p(adat->den, bdat->den));
+	    if (f_zero_p(adat->num) && f_zero_p(bdat->num))
+		return Qtrue;
+
+	    return f_boolcast(f_eqeq_p(adat->num, bdat->num) &&
+			      f_eqeq_p(adat->den, bdat->den));
 	}
       default:
-	return f_equal_p(other, self);
+	return f_eqeq_p(other, self);
     }
 }
 
+/* :nodoc: */
 static VALUE
-nurat_coerce(VALUE self, VALUE other)
+nurat_coerce(VALUE self, SEL sel, VALUE other)
 {
     switch (TYPE(other)) {
       case T_FIXNUM:
@@ -951,6 +1078,12 @@
 	return rb_assoc_new(f_rational_new_bang1(CLASS_OF(self), other), self);
       case T_FLOAT:
 	return rb_assoc_new(other, f_to_f(self));
+      case T_RATIONAL:
+	return rb_assoc_new(other, self);
+      case T_COMPLEX:
+	if (k_exact_zero_p(RCOMPLEX(other)->imag))
+	    return rb_assoc_new(f_rational_new_bang1
+				(CLASS_OF(self), RCOMPLEX(other)->real), self);
     }
 
     rb_raise(rb_eTypeError, "%s can't be coerced into %s",
@@ -958,43 +1091,23 @@
     return Qnil;
 }
 
+#if 0
+/* :nodoc: */
 static VALUE
 nurat_idiv(VALUE self, VALUE other)
 {
-    return f_floor(f_div(self, other));
+    return f_idiv(self, other);
 }
 
+/* :nodoc: */
 static VALUE
-nurat_mod(VALUE self, VALUE other)
-{
-    VALUE val = f_floor(f_div(self, other));
-    return f_sub(self, f_mul(other, val));
-}
-
-static VALUE
-nurat_divmod(VALUE self, VALUE other)
-{
-    VALUE val = f_floor(f_div(self, other));
-    return rb_assoc_new(val, f_sub(self, f_mul(other, val)));
-}
-
-#if 0
-static VALUE
 nurat_quot(VALUE self, VALUE other)
 {
     return f_truncate(f_div(self, other));
 }
-#endif
 
+/* :nodoc: */
 static VALUE
-nurat_rem(VALUE self, VALUE other)
-{
-    VALUE val = f_truncate(f_div(self, other));
-    return f_sub(self, f_mul(other, val));
-}
-
-#if 0
-static VALUE
 nurat_quotrem(VALUE self, VALUE other)
 {
     VALUE val = f_truncate(f_div(self, other));
@@ -1002,16 +1115,8 @@
 }
 #endif
 
-static VALUE
-nurat_abs(VALUE self)
-{
-    if (!f_negative_p(self))
-	return self;
-    else
-	return f_negate(self);
-}
-
 #if 0
+/* :nodoc: */
 static VALUE
 nurat_true(VALUE self)
 {
@@ -1020,21 +1125,39 @@
 #endif
 
 static VALUE
-nurat_floor(VALUE self)
+nurat_floor(VALUE self, SEL sel)
 {
     get_dat1(self);
     return f_idiv(dat->num, dat->den);
 }
 
 static VALUE
-nurat_ceil(VALUE self)
+nurat_ceil(VALUE self, SEL sel)
 {
     get_dat1(self);
     return f_negate(f_idiv(f_negate(dat->num), dat->den));
 }
 
+
+/*
+ * call-seq:
+ *    rat.to_i  ->  integer
+ *
+ * Returns the truncated value as an integer.
+ *
+ * Equivalent to
+ *    rat.truncate.
+ *
+ * For example:
+ *
+ *    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)
+nurat_truncate(VALUE self, SEL sel)
 {
     get_dat1(self);
     if (f_negative_p(dat->num))
@@ -1043,158 +1166,291 @@
 }
 
 static VALUE
-nurat_round(VALUE self)
+nurat_round(VALUE self, SEL sel)
 {
+    VALUE num, den, neg;
+
     get_dat1(self);
 
-    if (f_negative_p(dat->num)) {
-	VALUE num, den;
+    num = dat->num;
+    den = dat->den;
+    neg = f_negative_p(num);
 
-	num = f_negate(dat->num);
-	num = f_add(f_mul(num, TWO), dat->den);
-	den = f_mul(dat->den, TWO);
-	return f_negate(f_idiv(num, den));
-    }
-    else {
-	VALUE num = f_add(f_mul(dat->num, TWO), dat->den);
-	VALUE den = f_mul(dat->den, TWO);
-	return f_idiv(num, den);
-    }
-}
+    if (neg)
+	num = f_negate(num);
 
-#define f_size(x) rb_funcall(x, rb_intern("size"), 0)
-#define f_rshift(x,y) rb_funcall(x, rb_intern(">>"), 1, y)
+    num = f_add(f_mul(num, TWO), den);
+    den = f_mul(den, TWO);
+    num = f_idiv(num, den);
 
-inline static long
-i_ilog2(VALUE x)
-{
-    long q, r, fx;
+    if (neg)
+	num = f_negate(num);
 
-    assert(!f_lt_p(x, ONE));
-
-    q = (NUM2LONG(f_size(x)) - sizeof(long)) * 8 + 1;
-
-    if (q > 0)
-	x = f_rshift(x, LONG2NUM(q));
-
-    fx = NUM2LONG(x);
-
-    r = -1;
-    while (fx) {
-	fx >>= 1;
-	r += 1;
-    }
-
-    return q + r;
+    return num;
 }
 
 static VALUE
-nurat_to_f(VALUE self)
+f_round_common(int argc, VALUE *argv, VALUE self, VALUE (*func)(VALUE, SEL))
 {
-    VALUE num, den;
-    int minus = 0;
-    long nl, dl, ml, ne, de;
-    int e;
-    double f;
+    VALUE n, b, s;
 
-    {
-	get_dat1(self);
+    if (argc == 0)
+	return (*func)(self, NULL);
 
-	if (f_zero_p(dat->num))
-	    return rb_float_new(0.0);
+    rb_scan_args(argc, argv, "01", &n);
 
-	num = dat->num;
-	den = dat->den;
-    }
+    if (!k_integer_p(n))
+	rb_raise(rb_eTypeError, "not an integer");
 
-    if (f_negative_p(num)) {
-	num = f_negate(num);
-	minus = 1;
-    }
+    b = f_expt(INT2FIX(10), n);
+    s = f_mul(self, b);
 
-    nl = i_ilog2(num);
-    dl = i_ilog2(den);
-    ml = (long)(log(DBL_MAX) / log(2.0) - 1); /* should be a static */
+    s = (*func)(s, NULL);
 
-    ne = 0;
-    if (nl > ml) {
-	ne = nl - ml;
-	num = f_rshift(num, LONG2NUM(ne));
-    }
+    s = f_div(f_rational_new_bang1(CLASS_OF(self), s), b);
 
-    de = 0;
-    if (dl > ml) {
-	de = dl - ml;
-	den = f_rshift(den, LONG2NUM(de));
-    }
+    if (f_lt_p(n, ONE))
+	s = f_to_i(s);
 
-    e = (int)(ne - de);
+    return s;
+}
 
-    if ((e > DBL_MAX_EXP) || (e < DBL_MIN_EXP)) {
-	rb_warning("%s out of Float range", rb_obj_classname(self));
-	return rb_float_new(e > 0 ? HUGE_VAL : 0.0);
-    }
+/*
+ * call-seq:
+ *    rat.floor               ->  integer
+ *    rat.floor(precision=0)  ->  rational
+ *
+ * Returns the truncated value (toward negative infinity).
+ *
+ * For example:
+ *
+ *    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(VALUE self, SEL sel, int argc, VALUE *argv)
+{
+    return f_round_common(argc, argv, self, nurat_floor);
+}
 
-    f = NUM2DBL(num) / NUM2DBL(den);
-    if (minus)
-	f = -f;
-    f = ldexp(f, e);
+/*
+ * call-seq:
+ *    rat.ceil               ->  integer
+ *    rat.ceil(precision=0)  ->  rational
+ *
+ * Returns the truncated value (toward positive infinity).
+ *
+ * For example:
+ *
+ *    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(VALUE self, SEL sel, int argc, VALUE *argv)
+{
+    return f_round_common(argc, argv, self, nurat_ceil);
+}
 
-    if (isinf(f) || isnan(f))
-	rb_warning("%s out of Float range", rb_obj_classname(self));
+/*
+ * call-seq:
+ *    rat.truncate               ->  integer
+ *    rat.truncate(precision=0)  ->  rational
+ *
+ * Returns the truncated value (toward zero).
+ *
+ * For example:
+ *
+ *    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(VALUE self, SEL sel, int argc, VALUE *argv)
+{
+    return f_round_common(argc, argv, self, nurat_truncate);
+}
 
-    return rb_float_new(f);
+/*
+ * call-seq:
+ *    rat.round               ->  integer
+ *    rat.round(precision=0)  ->  rational
+ *
+ * Returns the truncated value (toward the nearest integer;
+ * 0.5 => 1; -0.5 => -1).
+ *
+ * For example:
+ *
+ *    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(VALUE self, SEL sel, int argc, VALUE *argv)
+{
+    return f_round_common(argc, argv, self, nurat_round);
 }
 
+/*
+ * call-seq:
+ *    rat.to_f  ->  float
+ *
+ * Return the value as a float.
+ *
+ * For example:
+ *
+ *    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_r(VALUE self)
+nurat_to_f(VALUE self, SEL sel)
 {
+    get_dat1(self);
+    return f_fdiv(dat->num, dat->den);
+}
+
+/*
+ * call-seq:
+ *    rat.to_r  ->  self
+ *
+ * Returns self.
+ *
+ * For example:
+ *
+ *    Rational(2).to_r      #=> (2/1)
+ *    Rational(-8, 6).to_r  #=> (-4/3)
+ */
+static VALUE
+nurat_to_r(VALUE self, SEL sel)
+{
     return self;
 }
 
+/* :nodoc: */
 static VALUE
-nurat_hash(VALUE self)
+nurat_hash(VALUE self, SEL sel)
 {
+    long v, h[2];
+    VALUE n;
+
     get_dat1(self);
-    return f_xor(dat->num, dat->den);
+    n = rb_hash(dat->num);
+    h[0] = NUM2LONG(n);
+    n = rb_hash(dat->den);
+    h[1] = NUM2LONG(n);
+    v = rb_memhash(h, sizeof(h));
+    return LONG2FIX(v);
 }
 
 static VALUE
-nurat_to_s(VALUE self)
+f_format(VALUE self, VALUE (*func)(VALUE))
 {
+    VALUE s;
     get_dat1(self);
 
-    if (f_one_p(dat->den))
-	return f_to_s(dat->num);
-    else
-	return rb_funcall(rb_mKernel, id_format, 3,
-			  rb_str_new2("%d/%d"), dat->num, dat->den);
+    s = (*func)(dat->num);
+    rb_str_cat2(s, "/");
+    rb_str_concat(s, (*func)(dat->den));
+
+    return s;
 }
 
+/*
+ * call-seq:
+ *    rat.to_s  ->  string
+ *
+ * Returns the value as a string.
+ *
+ * For example:
+ *
+ *    Rational(2).to_s      #=> "2/1"
+ *    Rational(-8, 6).to_s  #=> "-4/3"
+ *    Rational('0.5').to_s  #=> "1/2"
+ */
 static VALUE
-nurat_inspect(VALUE self)
+nurat_to_s(VALUE self, SEL sel)
 {
-    get_dat1(self);
-    return rb_funcall(rb_mKernel, id_format, 3,
-		      rb_str_new2("Rational(%d, %d)"), dat->num, dat->den);
+    return f_format(self, f_to_s);
 }
 
+/*
+ * call-seq:
+ *    rat.inspect  ->  string
+ *
+ * Returns the value as a string for inspection.
+ *
+ * For example:
+ *
+ *    Rational(2).inspect      #=> "(2/1)"
+ *    Rational(-8, 6).inspect  #=> "(-4/3)"
+ *    Rational('0.5').inspect  #=> "(1/2)"
+ */
 static VALUE
-nurat_marshal_dump(VALUE self)
+nurat_inspect(VALUE self, SEL sel)
 {
+    VALUE s;
+
+    s = rb_usascii_str_new2("(");
+    rb_str_concat(s, f_format(self, f_inspect));
+    rb_str_cat2(s, ")");
+
+    return s;
+}
+
+/* :nodoc: */
+static VALUE
+nurat_marshal_dump(VALUE self, SEL sel)
+{
+    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;
 }
 
+/* :nodoc: */
 static VALUE
-nurat_marshal_load(VALUE self, VALUE a)
+nurat_marshal_load(VALUE self, SEL sel, VALUE a)
 {
     get_dat1(self);
-    dat->num = RARRAY_AT(a, 0);
-    dat->den = RARRAY_AT(a, 1);
+    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(rb_eZeroDivError, "devided by zero");
+	rb_raise_zerodiv();
 
     return self;
 }
@@ -1202,23 +1458,68 @@
 /* --- */
 
 VALUE
-rb_gcd(VALUE self, VALUE other)
+rb_rational_reciprocal(VALUE x, SEL sel)
 {
-    nurat_int_check(other);
+    get_dat1(x);
+    return f_rational_new_no_reduce2(CLASS_OF(x), dat->den, dat->num);
+}
+
+/*
+ * call-seq:
+ *    int.gcd(int2)  ->  integer
+ *
+ * Returns the greatest common divisor (always positive).  0.gcd(x)
+ * and x.gcd(0) return abs(x).
+ *
+ * For example:
+ *
+ *    2.gcd(2)                    #=> 2
+ *    3.gcd(-7)                   #=> 1
+ *    ((1<<31)-1).gcd((1<<61)-1)  #=> 1
+ */
+VALUE
+rb_gcd(VALUE self, SEL sel, VALUE other)
+{
+    other = nurat_int_value(other);
     return f_gcd(self, other);
 }
 
+/*
+ * call-seq:
+ *    int.lcm(int2)  ->  integer
+ *
+ * Returns the least common multiple (always positive).  0.lcm(x) and
+ * x.lcm(0) return zero.
+ *
+ * For example:
+ *
+ *    2.lcm(2)                    #=> 2
+ *    3.lcm(-7)                   #=> 21
+ *    ((1<<31)-1).lcm((1<<61)-1)  #=> 4951760154835678088235319297
+ */
 VALUE
-rb_lcm(VALUE self, VALUE other)
+rb_lcm(VALUE self, SEL sel, VALUE other)
 {
-    nurat_int_check(other);
+    other = nurat_int_value(other);
     return f_lcm(self, other);
 }
 
+/*
+ * call-seq:
+ *    int.gcdlcm(int2)  ->  array
+ *
+ * Returns an array; [int.gcd(int2), int.lcm(int2)].
+ *
+ * For example:
+ *
+ *    2.gcdlcm(2)                    #=> [2, 2]
+ *    3.gcdlcm(-7)                   #=> [1, 21]
+ *    ((1<<31)-1).gcdlcm((1<<61)-1)  #=> [1, 4951760154835678088235319297]
+ */
 VALUE
-rb_gcdlcm(VALUE self, VALUE other)
+rb_gcdlcm(VALUE self, SEL sel, VALUE other)
 {
-    nurat_int_check(other);
+    other = nurat_int_value(other);
     return rb_assoc_new(f_gcd(self, other), f_lcm(self, other));
 }
 
@@ -1234,7 +1535,7 @@
     return nurat_s_canonicalize_internal(rb_cRational, x, y);
 }
 
-static VALUE nurat_s_convert(int argc, VALUE *argv, VALUE klass);
+static VALUE nurat_s_convert(VALUE klass, SEL sel, int argc, VALUE *argv);
 
 VALUE
 rb_Rational(VALUE x, VALUE y)
@@ -1242,23 +1543,138 @@
     VALUE a[2];
     a[0] = x;
     a[1] = y;
-    return nurat_s_convert(2, a, rb_cRational);
+    return nurat_s_convert(rb_cRational, NULL, 2, a);
 }
 
+#define id_numerator rb_intern("numerator")
+#define f_numerator(x) rb_funcall(x, id_numerator, 0)
+
+#define id_denominator rb_intern("denominator")
+#define f_denominator(x) rb_funcall(x, id_denominator, 0)
+
+#define id_to_r rb_intern("to_r")
+#define f_to_r(x) rb_funcall(x, id_to_r, 0)
+
+/*
+ * call-seq:
+ *    num.numerator  ->  integer
+ *
+ * Returns the numerator.
+ */
 static VALUE
-nilclass_to_r(VALUE self)
+numeric_numerator(VALUE self, SEL sel)
 {
+    return f_numerator(f_to_r(self));
+}
+
+/*
+ * call-seq:
+ *    num.denominator  ->  integer
+ *
+ * Returns the denominator (always positive).
+ */
+static VALUE
+numeric_denominator(VALUE self, SEL sel)
+{
+    return f_denominator(f_to_r(self));
+}
+
+/*
+ * call-seq:
+ *    int.numerator  ->  self
+ *
+ * Returns self.
+ */
+static VALUE
+integer_numerator(VALUE self, SEL sel)
+{
+    return self;
+}
+
+/*
+ * call-seq:
+ *    int.denominator  ->  1
+ *
+ * Returns 1.
+ */
+static VALUE
+integer_denominator(VALUE self, SEL sel)
+{
+    return INT2FIX(1);
+}
+
+/*
+ * call-seq:
+ *    flo.numerator  ->  integer
+ *
+ * Returns the numerator.  The result is machine dependent.
+ *
+ * For example:
+ *
+ *    n = 0.3.numerator    #=> 5404319552844595
+ *    d = 0.3.denominator  #=> 18014398509481984
+ *    n.fdiv(d)            #=> 0.3
+ */
+static VALUE
+float_numerator(VALUE self, SEL sel)
+{
+    double d = RFLOAT_VALUE(self);
+    if (isinf(d) || isnan(d))
+	return self;
+    return ZERO;
+//    return rb_call_super(0, 0);
+}
+
+/*
+ * call-seq:
+ *    flo.denominator  ->  integer
+ *
+ * Returns the denominator (always positive).  The result is machine
+ * dependent.
+ *
+ * See numerator.
+ */
+static VALUE
+float_denominator(VALUE self, SEL sel)
+{
+    double d = RFLOAT_VALUE(self);
+    if (isinf(d) || isnan(d))
+	return INT2FIX(1);
+    return ZERO;
+//    return rb_call_super(0, 0);
+}
+
+/*
+ * call-seq:
+ *    nil.to_r  ->  (0/1)
+ *
+ * Returns zero as a rational.
+ */
+static VALUE
+nilclass_to_r(VALUE self, SEL sel)
+{
     return rb_rational_new1(INT2FIX(0));
 }
 
+/*
+ * call-seq:
+ *    int.to_r  ->  rational
+ *
+ * Returns the value as a rational.
+ *
+ * For example:
+ *
+ *    1.to_r        #=> (1/1)
+ *    (1<<64).to_r  #=> (18446744073709551616/1)
+ */
 static VALUE
-integer_to_r(VALUE self)
+integer_to_r(VALUE self, SEL sel)
 {
     return rb_rational_new1(self);
 }
 
-static VALUE
-float_decode(VALUE self)
+static void
+float_decode_internal(VALUE self, VALUE *rf, VALUE *rn)
 {
     double f;
     int n;
@@ -1266,52 +1682,102 @@
     f = frexp(RFLOAT_VALUE(self), &n);
     f = ldexp(f, DBL_MANT_DIG);
     n -= DBL_MANT_DIG;
-    return rb_assoc_new(f_to_i(rb_float_new(f)), INT2FIX(n));
+    *rf = rb_dbl2big(f);
+    *rn = INT2FIX(n);
 }
 
+#if 0
 static VALUE
-float_to_r(VALUE self)
+float_decode(VALUE self)
 {
-    VALUE a = float_decode(self);
-    return f_mul(RARRAY_AT(a, 0),
-		 f_expt(INT2FIX(FLT_RADIX), RARRAY_AT(a, 1)));
+    VALUE f, n;
+
+    float_decode_internal(self, &f, &n);
+    return rb_assoc_new(f, n);
 }
+#endif
 
+#define id_lshift rb_intern("<<")
+#define f_lshift(x,n) rb_funcall(x, id_lshift, 1, n)
+
+/*
+ * call-seq:
+ *    flt.to_r  ->  rational
+ *
+ * Returns the value as a rational.
+ *
+ * NOTE: 0.3.to_r isn't the same as '0.3'.to_r.  The latter is
+ * equivalent to '3/10'.to_r, but the former isn't so.
+ *
+ * For example:
+ *
+ *    2.0.to_r    #=> (2/1)
+ *    2.5.to_r    #=> (5/2)
+ *    -0.75.to_r  #=> (-3/4)
+ *    0.0.to_r    #=> (0/1)
+ */
+static VALUE
+float_to_r(VALUE self, SEL sel)
+{
+    VALUE f, n;
+
+    float_decode_internal(self, &f, &n);
+#if FLT_RADIX == 2
+    {
+	long ln = FIX2LONG(n);
+
+	if (ln == 0)
+	    return f_to_r(f);
+	if (ln > 0)
+	    return f_to_r(f_lshift(f, n));
+	ln = -ln;
+	return rb_rational_new2(f, f_lshift(ONE, INT2FIX(ln)));
+    }
+#else
+    return f_to_r(f_mul(f, f_expt(INT2FIX(FLT_RADIX), n)));
+#endif
+}
+
 static VALUE rat_pat, an_e_pat, a_dot_pat, underscores_pat, an_underscore;
 
-#define DIGITS "(?:\\d(?:_\\d|\\d)*)"
+#define WS "\\s*"
+#define DIGITS "(?:[0-9](?:_[0-9]|[0-9])*)"
 #define NUMERATOR "(?:" DIGITS "?\\.)?" DIGITS "(?:[eE][-+]?" DIGITS ")?"
-#define DENOMINATOR "[-+]?" DIGITS
-#define PATTERN "\\A([-+])?(" NUMERATOR ")(?:\\/(" DENOMINATOR "))?"
+#define DENOMINATOR DIGITS
+#define PATTERN "\\A" WS "([-+])?(" NUMERATOR ")(?:\\/(" DENOMINATOR "))?" WS
 
 static void
 make_patterns(void)
 {
-    static char rat_pat_source[] = PATTERN;
-    static char an_e_pat_source[] = "[eE]";
-    static char a_dot_pat_source[] = "\\.";
-    static char underscores_pat_source[] = "_+";
+    static const char rat_pat_source[] = PATTERN;
+    static const char an_e_pat_source[] = "[eE]";
+    static const char a_dot_pat_source[] = "\\.";
+    static const char underscores_pat_source[] = "_+";
 
+    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("_");
+    an_underscore = rb_usascii_str_new2("_");
     rb_global_variable(&an_underscore);
+//    rb_gc_register_mark_object(an_underscore);
 }
 
-#define id_strip rb_intern("strip")
-#define f_strip(x) rb_funcall(x, id_strip, 0)
-
 #define id_match rb_intern("match")
 #define f_match(x,y) rb_funcall(x, id_match, 1, y)
 
@@ -1324,6 +1790,9 @@
 #define id_split rb_intern("split")
 #define f_split(x,y) rb_funcall(x, id_split, 1, y)
 
+#define id_strip rb_intern("strip")
+#define f_strip(x) rb_funcall(x, id_strip, 0)
+
 #include <ctype.h>
 
 static VALUE
@@ -1331,7 +1800,7 @@
 {
     VALUE s, m;
 
-    s = f_strip(self);
+    s = self;
 
     if (RSTRING_LEN(s) == 0)
 	return rb_assoc_new(Qnil, self);
@@ -1349,18 +1818,18 @@
 	    VALUE a;
 
 	    a = f_split(nu, an_e_pat);
-	    ifp = RARRAY_AT(a, 0);
+	    ifp = RARRAY_PTR(a)[0];
 	    if (RARRAY_LEN(a) != 2)
 		exp = Qnil;
 	    else
-		exp = RARRAY_AT(a, 1);
+		exp = RARRAY_PTR(a)[1];
 
 	    a = f_split(ifp, a_dot_pat);
-	    ip = RARRAY_AT(a, 0);
+	    ip = RARRAY_PTR(a)[0];
 	    if (RARRAY_LEN(a) != 2)
 		fp = Qnil;
 	    else
-		fp = RARRAY_AT(a, 1);
+		fp = RARRAY_PTR(a)[1];
 	}
 
 	v = rb_rational_new1(f_to_i(ip));
@@ -1381,10 +1850,14 @@
 	    v = f_add(v, f_to_i(fp));
 	    v = f_div(v, l);
 	}
+	if (!NIL_P(si) && *StringValuePtr(si) == '-')
+	    v = f_negate(v);
 	if (!NIL_P(exp))
 	    v = f_mul(v, f_expt(INT2FIX(10), f_to_i(exp)));
-	if (!NIL_P(si) && *StringValuePtr(si) == '-')
-	    v = f_negate(v);
+#if 0
+	if (!NIL_P(de) && (!NIL_P(fp) || !NIL_P(exp)))
+	    return rb_assoc_new(v, rb_usascii_str_new2("dummy"));
+#endif
 	if (!NIL_P(de))
 	    v = f_div(v, f_to_i(de));
 
@@ -1397,24 +1870,55 @@
 string_to_r_strict(VALUE self)
 {
     VALUE a = string_to_r_internal(self);
-    if (NIL_P(RARRAY_AT(a, 0)) || RSTRING_LEN(RARRAY_AT(a, 1)) > 0) {
+    if (NIL_P(RARRAY_PTR(a)[0]) || RSTRING_LEN(RARRAY_PTR(a)[1]) > 0) {
 	VALUE s = f_inspect(self);
-	rb_raise(rb_eArgError, "invalid value for Rational: %s",
+	rb_raise(rb_eArgError, "invalid value for convert(): %s",
 		 StringValuePtr(s));
     }
-    return RARRAY_AT(a, 0);
+    return RARRAY_PTR(a)[0];
 }
 
 #define id_gsub rb_intern("gsub")
 #define f_gsub(x,y,z) rb_funcall(x, id_gsub, 2, y, z)
 
+/*
+ * call-seq:
+ *    str.to_r  ->  rational
+ *
+ * Returns a rational which denotes the string form.  The parser
+ * ignores leading whitespaces and trailing garbage.  Any digit
+ * sequences can be separeted by an underscore.  Returns zero for null
+ * or garbage string.
+ *
+ * NOTE: '0.3'.to_r isn't the same as 0.3.to_r.  The former is
+ * equivalent to '3/10'.to_r, but the latter isn't so.
+ *
+ * For example:
+ *
+ *    '  2  '.to_r       #=> (2/1)
+ *    '300/2'.to_r       #=> (150/1)
+ *    '-9.2'.to_r        #=> (-46/5)
+ *    '-9.2e2'.to_r      #=> (-920/1)
+ *    '1_234_567'.to_r   #=> (1234567/1)
+ *    '21 june 09'.to_r  #=> (21/1)
+ *    '21/06/09'.to_r    #=> (7/2)
+ *    'bwv 1079'.to_r    #=> (0/1)
+ */
 static VALUE
-string_to_r(VALUE self)
+string_to_r(VALUE self, SEL sel)
 {
-    VALUE s = f_gsub(self, underscores_pat, an_underscore);
-    VALUE a = string_to_r_internal(s);
-    if (!NIL_P(RARRAY_AT(a, 0)))
-	return RARRAY_AT(a, 0);
+    VALUE s, a, backref;
+
+    backref = rb_backref_get();
+    rb_match_busy(backref);
+
+    s = f_gsub(self, underscores_pat, an_underscore);
+    a = string_to_r_internal(s);
+
+    rb_backref_set(backref);
+
+    if (!NIL_P(RARRAY_PTR(a)[0]))
+	return RARRAY_PTR(a)[0];
     return rb_rational_new1(INT2FIX(0));
 }
 
@@ -1422,34 +1926,30 @@
 #define f_to_r(x) rb_funcall(x, id_to_r, 0)
 
 static VALUE
-nurat_s_convert(int argc, VALUE *argv, VALUE klass)
+nurat_s_convert(VALUE klass, SEL sel, int argc, VALUE *argv)
 {
-    VALUE a1, a2;
+    VALUE a1, a2, backref;
 
-    if (rb_scan_args(argc, argv, "02", &a1, &a2) == 1) {
-	a2 = ONE;
-    }
+    rb_scan_args(argc, argv, "11", &a1, &a2);
 
+    if (NIL_P(a1) || (argc == 2 && NIL_P(a2)))
+	rb_raise(rb_eTypeError, "can't convert nil into Rational");
+
     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_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_zero_p(RCOMPLEX(a2)->imag))
+	    a2 = RCOMPLEX(a2)->real;
     }
 
+    backref = rb_backref_get();
+    rb_match_busy(backref);
+
     switch (TYPE(a1)) {
       case T_FIXNUM:
       case T_BIGNUM:
@@ -1474,141 +1974,181 @@
 	break;
     }
 
+    rb_backref_set(backref);
+
     switch (TYPE(a1)) {
       case T_RATIONAL:
-	if (NIL_P(a2) || f_zero_p(a2))
+	if (argc == 1 || (k_exact_one_p(a2)))
 	    return a1;
-	else
+    }
+
+    if (argc == 1) {
+	if (!(k_numeric_p(a1) && k_integer_p(a1)))
+	    return rb_convert_type(a1, T_RATIONAL, "Rational", "to_r");
+    }
+    else {
+	if ((k_numeric_p(a1) && k_numeric_p(a2)) &&
+	    (!f_integer_p(a1) || !f_integer_p(a2)))
 	    return f_div(a1, a2);
     }
 
-    switch (TYPE(a2)) {
-      case T_RATIONAL:
-	return f_div(a1, a2);
+    {
+	VALUE argv2[2];
+	argv2[0] = a1;
+	argv2[1] = a2;
+	return nurat_s_new(argc, argv2, klass);
     }
-
-    return nurat_s_new(klass, a1, a2);
 }
 
-static VALUE
-nurat_s_induced_from(VALUE klass, VALUE n)
-{
-    return f_to_r(n);
-}
-
+/*
+ * A rational number can be represented as a paired integer number;
+ * a/b (b>0).  Where a is numerator and b is denominator.  Integer a
+ * equals rational a/1 mathematically.
+ *
+ * In ruby, you can create rational object with Rational or to_r
+ * method.  The return values will be irreducible.
+ *
+ *    Rational(1)      #=> (1/1)
+ *    Rational(2, 3)   #=> (2/3)
+ *    Rational(4, -6)  #=> (-2/3)
+ *    3.to_r           #=> (3/1)
+ *
+ * You can also create ratioanl object from floating-point numbers or
+ * strings.
+ *
+ *    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)
+ *
+ * A rational object is an exact number, which helps you to write
+ * program without any rounding errors.
+ *
+ *    10.times.inject(0){|t,| t + 0.1}              #=> 0.9999999999999999
+ *    10.times.inject(0){|t,| t + Rational('0.1')}  #=> (1/1)
+ *
+ * However, when an expression has inexact factor (numerical value or
+ * operation), will produce an inexact result.
+ *
+ *    Rational(10) / 3   #=> (10/3)
+ *    Rational(10) / 3.0 #=> 3.3333333333333335
+ *
+ *    Rational(-8) ** Rational(1, 3)
+ *                       #=> (1.0000000000000002+1.7320508075688772i)
+ */
 void
 Init_Rational(void)
 {
     assert(fprintf(stderr, "assert() is now active\n"));
 
-    id_Unify = rb_intern("Unify");
     id_abs = rb_intern("abs");
     id_cmp = rb_intern("<=>");
     id_convert = rb_intern("convert");
-    id_equal_p = rb_intern("==");
+    id_eqeq_p = rb_intern("==");
     id_expt = rb_intern("**");
+    id_fdiv = rb_intern("fdiv");
     id_floor = rb_intern("floor");
-    id_format = rb_intern("format");
     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");
     id_truncate = rb_intern("truncate");
 
-    rb_cRational = rb_define_class(RATIONAL_NAME, rb_cNumeric);
+    rb_cRational = rb_define_class("Rational", rb_cNumeric);
 
-    rb_define_alloc_func(rb_cRational, nurat_s_alloc);
-//    rb_funcall(rb_cRational, rb_intern("private_class_method"), 1,
-//	       ID2SYM(rb_intern("allocate")));
+    rb_objc_define_method(rb_cRational, "alloc", nurat_s_alloc, 0);
+    rb_undef_method(CLASS_OF(rb_cRational), "allocate");
 
-    rb_define_singleton_method(rb_cRational, "new!", nurat_s_new_bang, -1);
-//    rb_funcall(rb_cRational, rb_intern("private_class_method"), 1,
-//	       ID2SYM(rb_intern("new!")));
+#if 0
+    rb_define_private_method(CLASS_OF(rb_cRational), "new!", nurat_s_new_bang, -1);
+    rb_define_private_method(CLASS_OF(rb_cRational), "new", nurat_s_new, -1);
+#else
+    rb_undef_method(CLASS_OF(rb_cRational), "new");
+#endif
 
-    rb_define_singleton_method(rb_cRational, "new", nurat_s_new_m, -1);
-//    rb_funcall(rb_cRational, rb_intern("private_class_method"), 1,
-//	       ID2SYM(rb_intern("new")));
+    rb_objc_define_method(rb_mKernel, "Rational", nurat_f_rational, -1);
 
-    rb_define_global_function(RATIONAL_NAME, nurat_f_rational, -1);
+    rb_objc_define_method(rb_cRational, "numerator", nurat_numerator, 0);
+    rb_objc_define_method(rb_cRational, "denominator", nurat_denominator, 0);
 
-    rb_define_method(rb_cRational, "numerator", nurat_numerator, 0);
-    rb_define_method(rb_cRational, "denominator", nurat_denominator, 0);
+    rb_objc_define_method(rb_cRational, "+", nurat_add, 1);
+    rb_objc_define_method(rb_cRational, "-", nurat_sub, 1);
+    rb_objc_define_method(rb_cRational, "*", nurat_mul, 1);
+    rb_objc_define_method(rb_cRational, "/", nurat_div, 1);
+    rb_objc_define_method(rb_cRational, "quo", nurat_div, 1);
+    rb_objc_define_method(rb_cRational, "fdiv", nurat_fdiv, 1);
+    rb_objc_define_method(rb_cRational, "**", nurat_expt, 1);
 
-    rb_define_method(rb_cRational, "+", nurat_add, 1);
-    rb_define_method(rb_cRational, "-", nurat_sub, 1);
-    rb_define_method(rb_cRational, "*", nurat_mul, 1);
-    rb_define_method(rb_cRational, "/", nurat_div, 1);
-    rb_define_method(rb_cRational, "quo", nurat_div, 1);
-    rb_define_method(rb_cRational, "fdiv", nurat_fdiv, 1);
-    rb_define_method(rb_cRational, "**", nurat_expt, 1);
+    rb_objc_define_method(rb_cRational, "<=>", nurat_cmp, 1);
+    rb_objc_define_method(rb_cRational, "==", nurat_eqeq_p, 1);
+    rb_objc_define_method(rb_cRational, "coerce", nurat_coerce, 1);
 
-    rb_define_method(rb_cRational, "<=>", nurat_cmp, 1);
-    rb_define_method(rb_cRational, "==", nurat_equal_p, 1);
-    rb_define_method(rb_cRational, "coerce", nurat_coerce, 1);
-
-    rb_define_method(rb_cRational, "div", nurat_idiv, 1);
-#if NUBY
+#if 0 /* NUBY */
     rb_define_method(rb_cRational, "//", nurat_idiv, 1);
 #endif
-    rb_define_method(rb_cRational, "modulo", nurat_mod, 1);
-    rb_define_method(rb_cRational, "%", nurat_mod, 1);
-    rb_define_method(rb_cRational, "divmod", nurat_divmod, 1);
 
 #if 0
     rb_define_method(rb_cRational, "quot", nurat_quot, 1);
-#endif
-    rb_define_method(rb_cRational, "remainder", nurat_rem, 1);
-#if 0
     rb_define_method(rb_cRational, "quotrem", nurat_quotrem, 1);
 #endif
 
-    rb_define_method(rb_cRational, "abs", nurat_abs, 0);
-
 #if 0
     rb_define_method(rb_cRational, "rational?", nurat_true, 0);
     rb_define_method(rb_cRational, "exact?", nurat_true, 0);
 #endif
 
-    rb_define_method(rb_cRational, "floor", nurat_floor, 0);
-    rb_define_method(rb_cRational, "ceil", nurat_ceil, 0);
-    rb_define_method(rb_cRational, "truncate", nurat_truncate, 0);
-    rb_define_method(rb_cRational, "round", nurat_round, 0);
+    rb_objc_define_method(rb_cRational, "floor", nurat_floor_n, -1);
+    rb_objc_define_method(rb_cRational, "ceil", nurat_ceil_n, -1);
+    rb_objc_define_method(rb_cRational, "truncate", nurat_truncate_n, -1);
+    rb_objc_define_method(rb_cRational, "round", nurat_round_n, -1);
 
-    rb_define_method(rb_cRational, "to_i", nurat_truncate, 0);
-    rb_define_method(rb_cRational, "to_f", nurat_to_f, 0);
-    rb_define_method(rb_cRational, "to_r", nurat_to_r, 0);
+    rb_objc_define_method(rb_cRational, "to_i", nurat_truncate, 0);
+    rb_objc_define_method(rb_cRational, "to_f", nurat_to_f, 0);
+    rb_objc_define_method(rb_cRational, "to_r", nurat_to_r, 0);
 
-    rb_define_method(rb_cRational, "hash", nurat_hash, 0);
+    rb_objc_define_method(rb_cRational, "hash", nurat_hash, 0);
 
-    rb_define_method(rb_cRational, "to_s", nurat_to_s, 0);
-    rb_define_method(rb_cRational, "inspect", nurat_inspect, 0);
+    rb_objc_define_method(rb_cRational, "to_s", nurat_to_s, 0);
+    rb_objc_define_method(rb_cRational, "inspect", nurat_inspect, 0);
 
-    rb_define_method(rb_cRational, "marshal_dump", nurat_marshal_dump, 0);
-    rb_define_method(rb_cRational, "marshal_load", nurat_marshal_load, 1);
+    rb_objc_define_method(rb_cRational, "marshal_dump", nurat_marshal_dump, 0);
+    rb_objc_define_method(rb_cRational, "marshal_load", nurat_marshal_load, 1);
 
     /* --- */
 
-    rb_define_method(rb_cInteger, "gcd", rb_gcd, 1);
-    rb_define_method(rb_cInteger, "lcm", rb_lcm, 1);
-    rb_define_method(rb_cInteger, "gcdlcm", rb_gcdlcm, 1);
+    rb_objc_define_method(rb_cInteger, "gcd", rb_gcd, 1);
+    rb_objc_define_method(rb_cInteger, "lcm", rb_lcm, 1);
+    rb_objc_define_method(rb_cInteger, "gcdlcm", rb_gcdlcm, 1);
 
-    rb_define_method(rb_cNilClass, "to_r", nilclass_to_r, 0);
-    rb_define_method(rb_cInteger, "to_r", integer_to_r, 0);
-    rb_define_method(rb_cFloat, "to_r", float_to_r, 0);
+    rb_objc_define_method(rb_cNumeric, "numerator", numeric_numerator, 0);
+    rb_objc_define_method(rb_cNumeric, "denominator", numeric_denominator, 0);
 
+    rb_objc_define_method(rb_cInteger, "numerator", integer_numerator, 0);
+    rb_objc_define_method(rb_cInteger, "denominator", integer_denominator, 0);
+
+    rb_objc_define_method(rb_cFloat, "numerator", float_numerator, 0);
+    rb_objc_define_method(rb_cFloat, "denominator", float_denominator, 0);
+
+    rb_objc_define_method(rb_cNilClass, "to_r", nilclass_to_r, 0);
+    rb_objc_define_method(rb_cInteger, "to_r", integer_to_r, 0);
+    rb_objc_define_method(rb_cFloat, "to_r", float_to_r, 0);
+
     make_patterns();
 
-    rb_define_method(rb_cString, "to_r", string_to_r, 0);
+    rb_objc_define_method(rb_cString, "to_r", string_to_r, 0);
 
-    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_objc_define_method(*(VALUE *)rb_cRational, "convert", nurat_s_convert, -1);
+//    rb_define_private_method(CLASS_OF(rb_cRational), "convert", nurat_s_convert, -1);
+}
 
-    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:
+*/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20090729/581aa93d/attachment-0001.html>


More information about the macruby-changes mailing list