<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[2117] MacRuby/branches/experimental</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.macosforge.org/projects/ruby/changeset/2117">2117</a></dd>
<dt>Author</dt> <dd>lsansonetti@apple.com</dd>
<dt>Date</dt> <dd>2009-07-29 22:04:52 -0700 (Wed, 29 Jul 2009)</dd>
</dl>

<h3>Log Message</h3>
<pre>ported Rational and Complex to the new runtime APIs, patch by Dan Sinclair</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#MacRubybranchesexperimentalcomplexc">MacRuby/branches/experimental/complex.c</a></li>
<li><a href="#MacRubybranchesexperimentalincluderubyrubyh">MacRuby/branches/experimental/include/ruby/ruby.h</a></li>
<li><a href="#MacRubybranchesexperimentalnumericc">MacRuby/branches/experimental/numeric.c</a></li>
<li><a href="#MacRubybranchesexperimentalrationalc">MacRuby/branches/experimental/rational.c</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="MacRubybranchesexperimentalcomplexc"></a>
<div class="modfile"><h4>Modified: MacRuby/branches/experimental/complex.c (2116 => 2117)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>-  complex.c: Coded by Tadayoshi Funaba 2008
</del><ins>+  complex.c: Coded by Tadayoshi Funaba 2008,2009
</ins><span class="cx"> 
</span><span class="cx">   This implementation is based on Keiju Ishitsuka's Complex library
</span><span class="cx">   which is written in ruby.
</span><span class="lines">@@ -7,26 +7,21 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;ruby.h&quot;
</span><span class="cx"> #include &lt;math.h&gt;
</span><ins>+#include &quot;ruby/re.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> #define NDEBUG
</span><span class="cx"> #include &lt;assert.h&gt;
</span><span class="cx"> 
</span><del>-#ifndef COMPLEX_NAME
-#define COMPLEX_NAME &quot;Complex&quot;
-#endif
-
</del><span class="cx"> #define ZERO INT2FIX(0)
</span><span class="cx"> #define ONE INT2FIX(1)
</span><span class="cx"> #define TWO INT2FIX(2)
</span><span class="cx"> 
</span><span class="cx"> VALUE rb_cComplex;
</span><span class="cx"> 
</span><del>-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;
</del><ins>+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;
</ins><span class="cx"> 
</span><span class="cx"> #define f_boolcast(x) ((x) ? Qtrue : Qfalse)
</span><span class="cx"> 
</span><span class="lines">@@ -65,75 +60,56 @@
</span><span class="cx">     return rb_funcall(rb_mMath, id_##n, 2, x, y);\
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#define PRESERVE_SIGNEDZERO
+
</ins><span class="cx"> inline static VALUE
</span><span class="cx"> f_add(VALUE x, VALUE y)
</span><span class="cx"> {
</span><del>-    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;
</del><ins>+#ifndef PRESERVE_SIGNEDZERO
+    if (FIXNUM_P(y) &amp;&amp; FIX2LONG(y) == 0)
+        return x;
+    else if (FIXNUM_P(x) &amp;&amp; FIX2LONG(x) == 0)
+        return y;
+#endif
+    return rb_funcall(x, '+', 1, y);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><span class="cx"> f_cmp(VALUE x, VALUE y)
</span><span class="cx"> {
</span><del>-    VALUE r;
</del><span class="cx">     if (FIXNUM_P(x) &amp;&amp; FIXNUM_P(y)) {
</span><span class="cx">         long c = FIX2LONG(x) - FIX2LONG(y);
</span><span class="cx">         if (c &gt; 0)
</span><span class="cx">             c = 1;
</span><span class="cx">         else if (c &lt; 0)
</span><span class="cx">             c = -1;
</span><del>-        r = INT2FIX(c);
</del><ins>+        return INT2FIX(c);
</ins><span class="cx">     }
</span><del>-    else
-        r = rb_funcall(x, id_cmp, 1, y);
-    return r;
</del><ins>+    return rb_funcall(x, id_cmp, 1, y);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><span class="cx"> f_div(VALUE x, VALUE y)
</span><span class="cx"> {
</span><del>-    VALUE r;
</del><span class="cx">     if (FIXNUM_P(y) &amp;&amp; FIX2LONG(y) == 1)
</span><del>-        r = x;
-    else
-        r = rb_funcall(x, '/', 1, y);
-    return r;
</del><ins>+        return x;
+    return rb_funcall(x, '/', 1, y);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><span class="cx"> f_gt_p(VALUE x, VALUE y)
</span><span class="cx"> {
</span><del>-    VALUE r;
</del><span class="cx">     if (FIXNUM_P(x) &amp;&amp; FIXNUM_P(y))
</span><del>-        r = f_boolcast(FIX2LONG(x) &gt; FIX2LONG(y));
-    else
-        r = rb_funcall(x, '&gt;', 1, y);
-    return r;
</del><ins>+        return f_boolcast(FIX2LONG(x) &gt; FIX2LONG(y));
+    return rb_funcall(x, '&gt;', 1, y);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><span class="cx"> f_lt_p(VALUE x, VALUE y)
</span><span class="cx"> {
</span><del>-    VALUE r;
</del><span class="cx">     if (FIXNUM_P(x) &amp;&amp; FIXNUM_P(y))
</span><del>-        r = f_boolcast(FIX2LONG(x) &lt; FIX2LONG(y));
-    else
-        r = rb_funcall(x, '&lt;', 1, y);
-    return r;
</del><ins>+        return f_boolcast(FIX2LONG(x) &lt; FIX2LONG(y));
+    return rb_funcall(x, '&lt;', 1, y);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> binop(mod, '%')
</span><span class="lines">@@ -141,121 +117,120 @@
</span><span class="cx"> inline static VALUE
</span><span class="cx"> f_mul(VALUE x, VALUE y)
</span><span class="cx"> {
</span><del>-    VALUE r;
</del><ins>+#ifndef PRESERVE_SIGNEDZERO
</ins><span class="cx">     if (FIXNUM_P(y)) {
</span><del>-        long _iy = FIX2LONG(y);
-        if (_iy == 0) {
-            if (TYPE(x) == T_FLOAT)
-                r = rb_float_new(0.0);
-            else
-                r = ZERO;
</del><ins>+        long iy = FIX2LONG(y);
+        if (iy == 0) {
+            if (FIXNUM_P(x) || TYPE(x) == T_BIGNUM)
+                return ZERO;
</ins><span class="cx">         }
</span><del>-        else if (_iy == 1)
-            r = x;
-        else
-            r = rb_funcall(x, '*', 1, y);
</del><ins>+        else if (iy == 1)
+            return x;
</ins><span class="cx">     }
</span><span class="cx">     else if (FIXNUM_P(x)) {
</span><del>-        long _ix = FIX2LONG(x);
-        if (_ix == 0) {
-            if (TYPE(y) == T_FLOAT)
-                r = rb_float_new(0.0);
-            else
-                r = ZERO;
</del><ins>+        long ix = FIX2LONG(x);
+        if (ix == 0) {
+            if (FIXNUM_P(y) || TYPE(y) == T_BIGNUM)
+                return ZERO;
</ins><span class="cx">         }
</span><del>-        else if (_ix == 1)
-            r = y;
-        else
-            r = rb_funcall(x, '*', 1, y);
</del><ins>+        else if (ix == 1)
+            return y;
</ins><span class="cx">     }
</span><del>-    else
-        r = rb_funcall(x, '*', 1, y);
-    return r;
</del><ins>+#endif
+    return rb_funcall(x, '*', 1, y);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><span class="cx"> f_sub(VALUE x, VALUE y)
</span><span class="cx"> {
</span><del>-    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;
</del><ins>+#ifndef PRESERVE_SIGNEDZERO
+    if (FIXNUM_P(y) &amp;&amp; FIX2LONG(y) == 0)
+        return x;
+#endif
+    return rb_funcall(x, '-', 1, y);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-binop(xor, '^')
-
</del><span class="cx"> fun1(abs)
</span><span class="cx"> fun1(abs2)
</span><span class="cx"> fun1(arg)
</span><del>-fun1(conjugate)
</del><ins>+fun1(conj)
</ins><span class="cx"> fun1(denominator)
</span><del>-fun1(exact_p)
</del><span class="cx"> fun1(floor)
</span><ins>+fun1(imag)
</ins><span class="cx"> fun1(inspect)
</span><span class="cx"> fun1(negate)
</span><span class="cx"> fun1(numerator)
</span><del>-fun1(polar)
-fun1(scalar_p)
</del><ins>+fun1(real)
+fun1(real_p)
+
</ins><span class="cx"> fun1(to_f)
</span><span class="cx"> fun1(to_i)
</span><span class="cx"> fun1(to_r)
</span><span class="cx"> fun1(to_s)
</span><del>-fun1(truncate)
</del><span class="cx"> 
</span><span class="cx"> fun2(divmod)
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><del>-f_equal_p(VALUE x, VALUE y)
</del><ins>+f_eqeq_p(VALUE x, VALUE y)
</ins><span class="cx"> {
</span><del>-    VALUE r;
</del><span class="cx">     if (FIXNUM_P(x) &amp;&amp; FIXNUM_P(y))
</span><del>-        r = f_boolcast(FIX2LONG(x) == FIX2LONG(y));
-    else
-        r = rb_funcall(x, id_equal_p, 1, y);
-    return r;
</del><ins>+        return f_boolcast(FIX2LONG(x) == FIX2LONG(y));
+    return rb_funcall(x, id_eqeq_p, 1, y);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> fun2(expt)
</span><ins>+fun2(fdiv)
</ins><span class="cx"> fun2(idiv)
</span><span class="cx"> fun2(quo)
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><span class="cx"> f_negative_p(VALUE x)
</span><span class="cx"> {
</span><del>-    VALUE r;
</del><span class="cx">     if (FIXNUM_P(x))
</span><del>-        r = f_boolcast(FIX2LONG(x) &lt; 0);
-    else
-        r = rb_funcall(x, '&lt;', 1, ZERO);
-    return r;
</del><ins>+        return f_boolcast(FIX2LONG(x) &lt; 0);
+    return rb_funcall(x, '&lt;', 1, ZERO);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#define f_positive_p(x) (!f_negative_p(x))
+
</ins><span class="cx"> inline static VALUE
</span><span class="cx"> f_zero_p(VALUE x)
</span><span class="cx"> {
</span><del>-    VALUE r;
-    if (FIXNUM_P(x))
-        r = f_boolcast(FIX2LONG(x) == 0);
-    else
-        r = rb_funcall(x, id_equal_p, 1, ZERO);
-    return r;
</del><ins>+    switch (TYPE(x)) {
+      case T_FIXNUM:
+        return f_boolcast(FIX2LONG(x) == 0);
+      case T_BIGNUM:
+        return Qfalse;
+      case T_RATIONAL:
+      {
+          VALUE num = RRATIONAL(x)-&gt;num;
+
+          return f_boolcast(FIXNUM_P(num) &amp;&amp; FIX2LONG(num) == 0);
+      }
+    }
+    return rb_funcall(x, id_eqeq_p, 1, ZERO);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#define f_nonzero_p(x) (!f_zero_p(x))
+
</ins><span class="cx"> inline static VALUE
</span><span class="cx"> f_one_p(VALUE x)
</span><span class="cx"> {
</span><del>-    VALUE r;
-    if (FIXNUM_P(x))
-        r = f_boolcast(FIX2LONG(x) == 1);
-    else
-        r = rb_funcall(x, id_equal_p, 1, ONE);
-    return r;
</del><ins>+    switch (TYPE(x)) {
+      case T_FIXNUM:
+        return f_boolcast(FIX2LONG(x) == 1);
+      case T_BIGNUM:
+        return Qfalse;
+      case T_RATIONAL:
+      {
+          VALUE num = RRATIONAL(x)-&gt;num;
+          VALUE den = RRATIONAL(x)-&gt;den;
+
+          return f_boolcast(FIXNUM_P(num) &amp;&amp; FIX2LONG(num) == 1 &amp;&amp;
+                            FIXNUM_P(den) &amp;&amp; FIX2LONG(den) == 1);
+      }
+    }
+    return rb_funcall(x, id_eqeq_p, 1, ONE);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><span class="lines">@@ -277,6 +252,18 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><ins>+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
</ins><span class="cx"> k_float_p(VALUE x)
</span><span class="cx"> {
</span><span class="cx">     return f_kind_of_p(x, rb_cFloat);
</span><span class="lines">@@ -294,25 +281,11 @@
</span><span class="cx">     return f_kind_of_p(x, rb_cComplex);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-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;
-    }
-}
</del><ins>+#define k_exact_p(x) (!k_float_p(x))
+#define k_inexact_p(x) k_float_p(x)
</ins><span class="cx"> 
</span><del>-static VALUE
-nucomp_s_generic_p(VALUE klass, VALUE x)
-{
-    return f_generic_p(x);
-}
</del><ins>+#define k_exact_zero_p(x) (k_exact_p(x) &amp;&amp; f_zero_p(x))
+#define k_exact_one_p(x) (k_exact_p(x) &amp;&amp; f_one_p(x))
</ins><span class="cx"> 
</span><span class="cx"> #define get_dat1(x) \
</span><span class="cx">     struct RComplex *dat;\
</span><span class="lines">@@ -324,59 +297,76 @@
</span><span class="cx">     bdat = ((struct RComplex *)(y))
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><del>-nucomp_s_new_internal(VALUE klass, VALUE real, VALUE image)
</del><ins>+nucomp_s_new_internal(VALUE klass, VALUE real, VALUE imag)
</ins><span class="cx"> {
</span><span class="cx">     NEWOBJ(obj, struct RComplex);
</span><span class="cx">     OBJSETUP(obj, klass, T_COMPLEX);
</span><span class="cx"> 
</span><span class="cx">     obj-&gt;real = real;
</span><del>-    obj-&gt;image = image;
</del><ins>+    obj-&gt;imag = imag;
</ins><span class="cx"> 
</span><span class="cx">     return (VALUE)obj;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static VALUE
</span><del>-nucomp_s_alloc(VALUE klass)
</del><ins>+nucomp_s_alloc(VALUE klass, SEL sel)
</ins><span class="cx"> {
</span><span class="cx">     return nucomp_s_new_internal(klass, ZERO, ZERO);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#if 0
</ins><span class="cx"> static VALUE
</span><span class="cx"> nucomp_s_new_bang(int argc, VALUE *argv, VALUE klass)
</span><span class="cx"> {
</span><del>-    VALUE real, image;
</del><ins>+    VALUE real, imag;
</ins><span class="cx"> 
</span><del>-    switch (rb_scan_args(argc, argv, &quot;11&quot;, &amp;real, &amp;image)) {
</del><ins>+    switch (rb_scan_args(argc, argv, &quot;11&quot;, &amp;real, &amp;imag)) {
</ins><span class="cx">       case 1:
</span><span class="cx">         if (!k_numeric_p(real))
</span><span class="cx">             real = f_to_i(real);
</span><del>-        image = ZERO;
</del><ins>+        imag = ZERO;
</ins><span class="cx">         break;
</span><span class="cx">       default:
</span><span class="cx">         if (!k_numeric_p(real))
</span><span class="cx">             real = f_to_i(real);
</span><del>-        if (!k_numeric_p(image))
-            image = f_to_i(image);
</del><ins>+        if (!k_numeric_p(imag))
+            imag = f_to_i(imag);
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    return nucomp_s_new_internal(klass, real, image);
</del><ins>+    return nucomp_s_new_internal(klass, real, imag);
</ins><span class="cx"> }
</span><ins>+#endif
</ins><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><span class="cx"> f_complex_new_bang1(VALUE klass, VALUE x)
</span><span class="cx"> {
</span><ins>+    assert(!k_complex_p(x));
</ins><span class="cx">     return nucomp_s_new_internal(klass, x, ZERO);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><span class="cx"> f_complex_new_bang2(VALUE klass, VALUE x, VALUE y)
</span><span class="cx"> {
</span><ins>+    assert(!k_complex_p(x));
+    assert(!k_complex_p(y));
</ins><span class="cx">     return nucomp_s_new_internal(klass, x, y);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-#define f_unify_p(klass) rb_const_defined(klass, id_Unify)
</del><ins>+#ifdef CANONICALIZATION_FOR_MATHN
+#define CANON
+#endif
</ins><span class="cx"> 
</span><ins>+#ifdef CANON
+static int canonicalization = 0;
+
+void
+nucomp_canonicalization(int f)
+{
+    canonicalization = f;
+}
+#endif
+
</ins><span class="cx"> inline static void
</span><span class="cx"> nucomp_real_check(VALUE num)
</span><span class="cx"> {
</span><span class="lines">@@ -387,81 +377,73 @@
</span><span class="cx">       case T_RATIONAL:
</span><span class="cx">         break;
</span><span class="cx">       default:
</span><del>-        rb_raise(rb_eArgError, &quot;not a real&quot;);
</del><ins>+        if (!k_numeric_p(num) || !f_real_p(num))
+            rb_raise(rb_eArgError, &quot;not a real&quot;);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><del>-nucomp_s_canonicalize_internal(VALUE klass, VALUE real, VALUE image)
</del><ins>+nucomp_s_canonicalize_internal(VALUE klass, VALUE real, VALUE imag)
</ins><span class="cx"> {
</span><ins>+#ifdef CANON
</ins><span class="cx"> #define CL_CANON
</span><span class="cx"> #ifdef CL_CANON
</span><del>-    if (f_zero_p(image) &amp;&amp; f_unify_p(klass) &amp;&amp;
-        !k_float_p(real) &amp;&amp; !k_float_p(image))
</del><ins>+    if (k_exact_zero_p(imag) &amp;&amp; canonicalization)
</ins><span class="cx">         return real;
</span><span class="cx"> #else
</span><del>-    if (f_zero_p(image) &amp;&amp; f_unify_p(klass))
</del><ins>+    if (f_zero_p(imag) &amp;&amp; canonicalization)
</ins><span class="cx">         return real;
</span><span class="cx"> #endif
</span><del>-    else if (f_scalar_p(real) &amp;&amp; f_scalar_p(image))
-        return nucomp_s_new_internal(klass, real, image);
-    else if (f_scalar_p(real)) {
-        get_dat1(image);
</del><ins>+#endif
+    if (f_real_p(real) &amp;&amp; f_real_p(imag))
+        return nucomp_s_new_internal(klass, real, imag);
+    else if (f_real_p(real)) {
+        get_dat1(imag);
</ins><span class="cx"> 
</span><span class="cx">         return nucomp_s_new_internal(klass,
</span><del>-                                     f_sub(real, dat-&gt;image),
</del><ins>+                                     f_sub(real, dat-&gt;imag),
</ins><span class="cx">                                      f_add(ZERO, dat-&gt;real));
</span><span class="cx">     }
</span><del>-    else if (f_scalar_p(image)) {
</del><ins>+    else if (f_real_p(imag)) {
</ins><span class="cx">         get_dat1(real);
</span><span class="cx"> 
</span><span class="cx">         return nucomp_s_new_internal(klass,
</span><span class="cx">                                      dat-&gt;real,
</span><del>-                                     f_add(dat-&gt;image, image));
</del><ins>+                                     f_add(dat-&gt;imag, imag));
</ins><span class="cx">     }
</span><span class="cx">     else {
</span><del>-        get_dat2(real, image);
</del><ins>+        get_dat2(real, imag);
</ins><span class="cx"> 
</span><span class="cx">         return nucomp_s_new_internal(klass,
</span><del>-                                     f_sub(adat-&gt;real, bdat-&gt;image),
-                                     f_add(adat-&gt;image, bdat-&gt;real));
</del><ins>+                                     f_sub(adat-&gt;real, bdat-&gt;imag),
+                                     f_add(adat-&gt;imag, bdat-&gt;real));
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-#if 0
</del><ins>+/*
+ * call-seq:
+ *    Complex.rect(real[, imag])         -&gt;  complex
+ *    Complex.rectangular(real[, imag])  -&gt;  complex
+ *
+ * Returns a complex object which denotes the given rectangular form.
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_s_canonicalize(int argc, VALUE *argv, VALUE klass)
</del><ins>+nucomp_s_new(VALUE klass, SEL sel, int argc, VALUE *argv)
</ins><span class="cx"> {
</span><del>-    VALUE real, image;
</del><ins>+    VALUE real, imag;
</ins><span class="cx"> 
</span><del>-    switch (rb_scan_args(argc, argv, &quot;11&quot;, &amp;real, &amp;image)) {
</del><ins>+    switch (rb_scan_args(argc, argv, &quot;11&quot;, &amp;real, &amp;imag)) {
</ins><span class="cx">       case 1:
</span><del>-        image = ZERO;
</del><ins>+        nucomp_real_check(real);
+        imag = ZERO;
</ins><span class="cx">         break;
</span><del>-    }
-
-    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, &quot;11&quot;, &amp;real, &amp;image)) {
-      case 1:
-        image = ZERO;
</del><ins>+      default:
+        nucomp_real_check(real);
+        nucomp_real_check(imag);
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    nucomp_real_check(real);
-    nucomp_real_check(image);
-
-    return nucomp_s_canonicalize_internal(klass, real, image);
</del><ins>+    return nucomp_s_canonicalize_internal(klass, real, imag);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><span class="lines">@@ -478,82 +460,98 @@
</span><span class="cx">     return nucomp_s_canonicalize_internal(klass, x, y);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    Complex(x[, y])  -&gt;  numeric
+ *
+ * Returns x+i*y;
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_f_complex(int argc, VALUE *argv, VALUE klass)
</del><ins>+nucomp_f_complex(VALUE klass, SEL sel, int argc, VALUE *argv)
</ins><span class="cx"> {
</span><span class="cx">     return rb_funcall2(rb_cComplex, id_convert, argc, argv);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-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);
</del><ins>+#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)
+
</ins><span class="cx"> extern VALUE math_log(int argc, VALUE *argv);
</span><del>-extern VALUE math_sin(VALUE obj, VALUE x);
-extern VALUE math_sinh(VALUE obj, VALUE x);
-extern VALUE math_sqrt(VALUE obj, VALUE x);
</del><span class="cx"> 
</span><del>-#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)
-
</del><span class="cx"> static VALUE
</span><span class="cx"> m_log_bang(VALUE x)
</span><span class="cx"> {
</span><del>-  return math_log(1, &amp;x);
</del><ins>+    return math_log(1, &amp;x);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-#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)
</del><ins>+imp1(sin)
+imp1(sinh)
+imp1(sqrt)
</ins><span class="cx"> 
</span><span class="cx"> static VALUE
</span><span class="cx"> m_cos(VALUE x)
</span><span class="cx"> {
</span><del>-    get_dat1(x);
-
-    if (f_generic_p(x))
</del><ins>+    if (f_real_p(x))
</ins><span class="cx">         return m_cos_bang(x);
</span><del>-    else
</del><ins>+    {
+        get_dat1(x);
</ins><span class="cx">         return f_complex_new2(rb_cComplex,
</span><span class="cx">                               f_mul(m_cos_bang(dat-&gt;real),
</span><del>-                                    m_cosh_bang(dat-&gt;image)),
</del><ins>+                                    m_cosh_bang(dat-&gt;imag)),
</ins><span class="cx">                               f_mul(f_negate(m_sin_bang(dat-&gt;real)),
</span><del>-                                    m_sinh_bang(dat-&gt;image)));
</del><ins>+                                    m_sinh_bang(dat-&gt;imag)));
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static VALUE
</span><span class="cx"> m_sin(VALUE x)
</span><span class="cx"> {
</span><del>-    get_dat1(x);
-
-    if (f_generic_p(x))
</del><ins>+    if (f_real_p(x))
</ins><span class="cx">         return m_sin_bang(x);
</span><del>-    else
</del><ins>+    {
+        get_dat1(x);
</ins><span class="cx">         return f_complex_new2(rb_cComplex,
</span><span class="cx">                               f_mul(m_sin_bang(dat-&gt;real),
</span><del>-                                    m_cosh_bang(dat-&gt;image)),
</del><ins>+                                    m_cosh_bang(dat-&gt;imag)),
</ins><span class="cx">                               f_mul(m_cos_bang(dat-&gt;real),
</span><del>-                                    m_sinh_bang(dat-&gt;image)));
</del><ins>+                                    m_sinh_bang(dat-&gt;imag)));
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#if 0
</ins><span class="cx"> static VALUE
</span><span class="cx"> m_sqrt(VALUE x)
</span><span class="cx"> {
</span><del>-    if (f_generic_p(x)) {
-        if (!f_negative_p(x))
</del><ins>+    if (f_real_p(x)) {
+        if (f_positive_p(x))
</ins><span class="cx">             return m_sqrt_bang(x);
</span><del>-        else
-            return f_complex_new2(rb_cComplex, ZERO, m_sqrt_bang(f_negate(x)));
</del><ins>+        return f_complex_new2(rb_cComplex, ZERO, m_sqrt_bang(f_negate(x)));
</ins><span class="cx">     }
</span><span class="cx">     else {
</span><span class="cx">         get_dat1(x);
</span><span class="cx"> 
</span><del>-        if (f_negative_p(dat-&gt;image))
-            return f_conjugate(m_sqrt(f_conjugate(x)));
</del><ins>+        if (f_negative_p(dat-&gt;imag))
+            return f_conj(m_sqrt(f_conj(x)));
</ins><span class="cx">         else {
</span><span class="cx">             VALUE a = f_abs(x);
</span><span class="cx">             return f_complex_new2(rb_cComplex,
</span><span class="lines">@@ -562,347 +560,540 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> }
</span><ins>+#endif
</ins><span class="cx"> 
</span><ins>+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])  -&gt;  complex
+ *
+ * Returns a complex object which denotes the given polar form.
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_s_polar(VALUE klass, VALUE abs, VALUE arg)
</del><ins>+nucomp_s_polar(VALUE klass, SEL sel, int argc, VALUE *argv)
</ins><span class="cx"> {
</span><del>-    return f_complex_new2(klass,
-                          f_mul(abs, m_cos(arg)),
-                          f_mul(abs, m_sin(arg)));
</del><ins>+    VALUE abs, arg;
+
+    switch (rb_scan_args(argc, argv, &quot;11&quot;, &amp;abs, &amp;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);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    cmp.real  -&gt;  real
+ *
+ * Returns the real part.
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_real(VALUE self)
</del><ins>+nucomp_real(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><span class="cx">     get_dat1(self);
</span><span class="cx">     return dat-&gt;real;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    cmp.imag       -&gt;  real
+ *    cmp.imaginary  -&gt;  real
+ *
+ * Returns the imaginary part.
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_image(VALUE self)
</del><ins>+nucomp_imag(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><span class="cx">     get_dat1(self);
</span><del>-    return dat-&gt;image;
</del><ins>+    return dat-&gt;imag;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    -cmp  -&gt;  complex
+ *
+ * Returns negation of the value.
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_add(VALUE self, VALUE other)
</del><ins>+nucomp_negate(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><del>-    switch (TYPE(other)) {
-      case T_FIXNUM:
-      case T_BIGNUM:
-      case T_FLOAT:
-      case T_RATIONAL:
-        {
-            get_dat1(self);
</del><ins>+  get_dat1(self);
+  return f_complex_new2(CLASS_OF(self),
+                        f_negate(dat-&gt;real), f_negate(dat-&gt;imag));
+}
</ins><span class="cx"> 
</span><del>-            return f_complex_new2(CLASS_OF(self),
-                                  f_add(dat-&gt;real, other), dat-&gt;image);
-        }
-      case T_COMPLEX:
-        {
-            VALUE real, image;
</del><ins>+inline static VALUE
+f_addsub(VALUE self, VALUE other,
+         VALUE (*func)(VALUE, VALUE), ID id)
+{
+    if (k_complex_p(other)) {
+        VALUE real, imag;
</ins><span class="cx"> 
</span><del>-            get_dat2(self, other);
</del><ins>+        get_dat2(self, other);
</ins><span class="cx"> 
</span><del>-            real = f_add(adat-&gt;real, bdat-&gt;real);
-            image = f_add(adat-&gt;image, bdat-&gt;image);
</del><ins>+        real = (*func)(adat-&gt;real, bdat-&gt;real);
+        imag = (*func)(adat-&gt;imag, bdat-&gt;imag);
</ins><span class="cx"> 
</span><del>-            return f_complex_new2(CLASS_OF(self), real, image);
-        }
-      default:
-        return rb_num_coerce_bin(self, other, '+');
</del><ins>+        return f_complex_new2(CLASS_OF(self), real, imag);
</ins><span class="cx">     }
</span><ins>+    if (k_numeric_p(other) &amp;&amp; f_real_p(other)) {
+        get_dat1(self);
+
+        return f_complex_new2(CLASS_OF(self),
+                              (*func)(dat-&gt;real, other), dat-&gt;imag);
+    }
+    return rb_num_coerce_bin(self, other, id);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    cmp + numeric  -&gt;  complex
+ *
+ * Performs addition.
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_sub(VALUE self, VALUE other)
</del><ins>+nucomp_add(VALUE self, SEL sel, VALUE other)
</ins><span class="cx"> {
</span><del>-    switch (TYPE(other)) {
-      case T_FIXNUM:
-      case T_BIGNUM:
-      case T_FLOAT:
-      case T_RATIONAL:
-        {
-            get_dat1(self);
</del><ins>+    return f_addsub(self, other, f_add, '+');
+}
</ins><span class="cx"> 
</span><del>-            return f_complex_new2(CLASS_OF(self),
-                                  f_sub(dat-&gt;real, other), dat-&gt;image);
-        }
-      case T_COMPLEX:
-        {
-            VALUE real, image;
-
-            get_dat2(self, other);
-
-            real = f_sub(adat-&gt;real, bdat-&gt;real);
-            image = f_sub(adat-&gt;image, bdat-&gt;image);
-
-            return f_complex_new2(CLASS_OF(self), real, image);
-        }
-      default:
-        return rb_num_coerce_bin(self, other, '-');
-    }
</del><ins>+/*
+ * call-seq:
+ *    cmp - numeric  -&gt;  complex
+ *
+ * Performs subtraction.
+ */
+static VALUE
+nucomp_sub(VALUE self, SEL sel, VALUE other)
+{
+    return f_addsub(self, other, f_sub, '-');
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    cmp * numeric  -&gt;  complex
+ *
+ * Performs multiplication.
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_mul(VALUE self, VALUE other)
</del><ins>+nucomp_mul(VALUE self, SEL sel, VALUE other)
</ins><span class="cx"> {
</span><del>-    switch (TYPE(other)) {
-      case T_FIXNUM:
-      case T_BIGNUM:
-      case T_FLOAT:
-      case T_RATIONAL:
-        {
-            get_dat1(self);
</del><ins>+    if (k_complex_p(other)) {
+        VALUE real, imag;
</ins><span class="cx"> 
</span><del>-            return f_complex_new2(CLASS_OF(self),
-                                  f_mul(dat-&gt;real, other),
-                                  f_mul(dat-&gt;image, other));
-        }
-      case T_COMPLEX:
-        {
-            VALUE real, image;
</del><ins>+        get_dat2(self, other);
</ins><span class="cx"> 
</span><del>-            get_dat2(self, other);
</del><ins>+        real = f_sub(f_mul(adat-&gt;real, bdat-&gt;real),
+                     f_mul(adat-&gt;imag, bdat-&gt;imag));
+        imag = f_add(f_mul(adat-&gt;real, bdat-&gt;imag),
+                     f_mul(adat-&gt;imag, bdat-&gt;real));
</ins><span class="cx"> 
</span><del>-            real = f_sub(f_mul(adat-&gt;real, bdat-&gt;real),
-                         f_mul(adat-&gt;image, bdat-&gt;image));
-            image = f_add(f_mul(adat-&gt;real, bdat-&gt;image),
-                          f_mul(adat-&gt;image, bdat-&gt;real));
</del><ins>+        return f_complex_new2(CLASS_OF(self), real, imag);
+    }
+    if (k_numeric_p(other) &amp;&amp; f_real_p(other)) {
+        get_dat1(self);
</ins><span class="cx"> 
</span><del>-            return f_complex_new2(CLASS_OF(self), real, image);
-        }
-      default:
-        return rb_num_coerce_bin(self, other, '*');
</del><ins>+        return f_complex_new2(CLASS_OF(self),
+                              f_mul(dat-&gt;real, other),
+                              f_mul(dat-&gt;imag, other));
</ins><span class="cx">     }
</span><ins>+    return rb_num_coerce_bin(self, other, '*');
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-static VALUE
-nucomp_div(VALUE self, VALUE other)
</del><ins>+inline static VALUE
+f_divide(VALUE self, VALUE other,
+         VALUE (*func)(VALUE, VALUE), ID id)
</ins><span class="cx"> {
</span><del>-    switch (TYPE(other)) {
-      case T_FIXNUM:
-      case T_BIGNUM:
-      case T_FLOAT:
-      case T_RATIONAL:
-        {
-            get_dat1(self);
</del><ins>+    if (k_complex_p(other)) {
+        int flo;
+        get_dat2(self, other);
</ins><span class="cx"> 
</span><ins>+        flo = (k_float_p(adat-&gt;real) || k_float_p(adat-&gt;imag) ||
+               k_float_p(bdat-&gt;real) || k_float_p(bdat-&gt;imag));
+
+        if (f_gt_p(f_abs(bdat-&gt;real), f_abs(bdat-&gt;imag))) {
+            VALUE r, n;
+
+            r = (*func)(bdat-&gt;imag, bdat-&gt;real);
+            n = f_mul(bdat-&gt;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));
</ins><span class="cx">             return f_complex_new2(CLASS_OF(self),
</span><del>-                                  f_div(dat-&gt;real, other),
-                                  f_div(dat-&gt;image, other));
</del><ins>+                                  (*func)(f_add(adat-&gt;real,
+                                                f_mul(adat-&gt;imag, r)), n),
+                                  (*func)(f_sub(adat-&gt;imag,
+                                                f_mul(adat-&gt;real, r)), n));
</ins><span class="cx">         }
</span><del>-      case T_COMPLEX:
-        {
-            get_dat2(self, other);
</del><ins>+        else {
+            VALUE r, n;
</ins><span class="cx"> 
</span><del>-            if (TYPE(adat-&gt;real)  == T_FLOAT ||
-                TYPE(adat-&gt;image) == T_FLOAT ||
-                TYPE(bdat-&gt;real)  == T_FLOAT ||
-                TYPE(bdat-&gt;image) == T_FLOAT) {
-                VALUE magn = m_hypot(bdat-&gt;real, bdat-&gt;image);
-                VALUE tmp = f_complex_new_bang2(CLASS_OF(self),
-                                                f_div(bdat-&gt;real, magn),
-                                                f_div(bdat-&gt;image, magn));
-                return f_div(f_mul(self, f_conjugate(tmp)), magn);
-            }
-            return f_div(f_mul(self, f_conjugate(other)), f_abs2(other));
</del><ins>+            r = (*func)(bdat-&gt;real, bdat-&gt;imag);
+            n = f_mul(bdat-&gt;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-&gt;real, r),
+                                                adat-&gt;imag), n),
+                                  (*func)(f_sub(f_mul(adat-&gt;imag, r),
+                                                adat-&gt;real), n));
</ins><span class="cx">         }
</span><del>-      default:
-        return rb_num_coerce_bin(self, other, '/');
</del><span class="cx">     }
</span><ins>+    if (k_numeric_p(other) &amp;&amp; f_real_p(other)) {
+        get_dat1(self);
+
+        return f_complex_new2(CLASS_OF(self),
+                              (*func)(dat-&gt;real, other),
+                              (*func)(dat-&gt;imag, other));
+    }
+    return rb_num_coerce_bin(self, other, id);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#define rb_raise_zerodiv() rb_raise(rb_eZeroDivError, &quot;divided by 0&quot;)
+
+/*
+ * call-seq:
+ *    cmp / numeric     -&gt;  complex
+ *    cmp.quo(numeric)  -&gt;  complex
+ *
+ * Performs division.
+ *
+ * For example:
+ *
+ *     Complex(10.0) / 3  #=&gt; (3.3333333333333335+(0/1)*i)
+ *     Complex(10)   / 3  #=&gt; ((10/3)+(0/1)*i)  # not (3+0i)
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_quo(VALUE self, VALUE other)
</del><ins>+nucomp_div(VALUE self, SEL sel, VALUE other)
</ins><span class="cx"> {
</span><del>-    get_dat1(self);
</del><ins>+    return f_divide(self, other, f_quo, id_quo);
+}
</ins><span class="cx"> 
</span><del>-    return f_div(f_complex_new2(CLASS_OF(self),
-                                f_quo(dat-&gt;real, ONE),
-                                f_quo(dat-&gt;image, ONE)), other);
</del><ins>+#define nucomp_quo nucomp_div
+
+/*
+ * call-seq:
+ *    cmp.fdiv(numeric)  -&gt;  complex
+ *
+ * Performs division as each part is a float, never returns a float.
+ *
+ * For example:
+ *
+ *     Complex(11,22).fdiv(3)  #=&gt; (3.6666666666666665+7.333333333333333i)
+ */
+static VALUE
+nucomp_fdiv(VALUE self, SEL sel, VALUE other)
+{
+    return f_divide(self, other, f_fdiv, id_fdiv);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static VALUE
</span><del>-nucomp_fdiv(VALUE self, VALUE other)
</del><ins>+m_log(VALUE x)
</ins><span class="cx"> {
</span><del>-    get_dat1(self);
</del><ins>+    if (f_real_p(x) &amp;&amp; f_positive_p(x))
+        return m_log_bang(x);
+    return rb_complex_new2(m_log_bang(f_abs(x)), f_arg(x));
+}
</ins><span class="cx"> 
</span><del>-    return f_div(f_complex_new2(CLASS_OF(self),
-                                f_to_f(dat-&gt;real),
-                                f_to_f(dat-&gt;image)), other);
</del><ins>+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)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+VALUE
+rb_fexpt(VALUE x, VALUE y)
+{
+    if (f_zero_p(x) || (!k_float_p(x) &amp;&amp; !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  -&gt;  complex
+ *
+ * Performs exponentiation.
+ *
+ * For example:
+ *
+ *     Complex('i') ** 2             #=&gt; (-1+0i)
+ *     Complex(-8) ** Rational(1,3)  #=&gt; (1.0000000000000002+1.7320508075688772i)
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_expt(VALUE self, VALUE other)
</del><ins>+nucomp_expt(VALUE self, SEL sel, VALUE other)
</ins><span class="cx"> {
</span><del>-    if (f_zero_p(other))
</del><ins>+    if (k_exact_zero_p(other))
</ins><span class="cx">         return f_complex_new_bang1(CLASS_OF(self), ONE);
</span><span class="cx"> 
</span><span class="cx">     if (k_rational_p(other) &amp;&amp; f_one_p(f_denominator(other)))
</span><del>-        other = f_numerator(other); /* good? */
</del><ins>+        other = f_numerator(other); /* c14n */
</ins><span class="cx"> 
</span><del>-    switch (TYPE(other)) {
-      case T_FIXNUM:
-      case T_BIGNUM:
</del><ins>+    if (k_complex_p(other)) {
+        get_dat1(other);
+
+        if (k_exact_zero_p(dat-&gt;imag))
+            other = dat-&gt;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-&gt;real, m_log_bang(r)),
+                              f_mul(dat-&gt;imag, theta)));
+        ntheta = f_add(f_mul(theta, dat-&gt;real),
+                       f_mul(dat-&gt;imag, m_log_bang(r)));
+        return f_complex_polar(CLASS_OF(self), nr, ntheta);
+    }
+    if (k_fixnum_p(other)) {
</ins><span class="cx">         if (f_gt_p(other, ZERO)) {
</span><del>-            VALUE x, z, n;
</del><ins>+            VALUE x, z;
+            long n;
</ins><span class="cx"> 
</span><span class="cx">             x = self;
</span><span class="cx">             z = x;
</span><del>-            n = f_sub(other, ONE);
</del><ins>+            n = FIX2LONG(other) - 1;
</ins><span class="cx"> 
</span><del>-            while (!f_zero_p(n)) {
-                VALUE a;
</del><ins>+            while (n) {
+                long q, r;
</ins><span class="cx"> 
</span><del>-                while (a = f_divmod(n, TWO),
-                       f_zero_p(RARRAY_AT(a, 1))) {
</del><ins>+                while (1) {
</ins><span class="cx">                     get_dat1(x);
</span><span class="cx"> 
</span><ins>+                    q = n / 2;
+                    r = n % 2;
+
+                    if (r)
+                        break;
+
</ins><span class="cx">                     x = f_complex_new2(CLASS_OF(self),
</span><span class="cx">                                        f_sub(f_mul(dat-&gt;real, dat-&gt;real),
</span><del>-                                             f_mul(dat-&gt;image, dat-&gt;image)),
-                                       f_mul(f_mul(TWO, dat-&gt;real), dat-&gt;image));
-                    n = RARRAY_AT(a, 0);
</del><ins>+                                             f_mul(dat-&gt;imag, dat-&gt;imag)),
+                                       f_mul(f_mul(TWO, dat-&gt;real), dat-&gt;imag));
+                    n = q;
</ins><span class="cx">                 }
</span><span class="cx">                 z = f_mul(z, x);
</span><del>-                n = f_sub(n, ONE);
</del><ins>+                n--;
</ins><span class="cx">             }
</span><span class="cx">             return z;
</span><span class="cx">         }
</span><del>-        else {
-            return f_expt(f_div(f_to_r(ONE), self), f_negate(other));
-        }
-      case T_FLOAT:
-      case T_RATIONAL:
-        {
-            VALUE a, r, theta;
</del><ins>+        return f_expt(f_reciprocal(self), f_negate(other));
+    }
+    if (k_numeric_p(other) &amp;&amp; f_real_p(other)) {
+        VALUE r, theta;
</ins><span class="cx"> 
</span><del>-            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;
</del><ins>+        if (k_bignum_p(other))
+            rb_warn(&quot;in a**b, b may be too big&quot;);
</ins><span class="cx"> 
</span><del>-            get_dat1(other);
</del><ins>+        r = f_abs(self);
+        theta = f_arg(self);
</ins><span class="cx"> 
</span><del>-            a = f_polar(self);
-            r = RARRAY_AT(a, 0);
-            theta = RARRAY_AT(a, 1);
-
-            ore = dat-&gt;real;
-            oim = dat-&gt;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);
</del><ins>+        return f_complex_polar(CLASS_OF(self), f_expt(r, other),
+                               f_mul(theta, other));
</ins><span class="cx">     }
</span><ins>+    return rb_num_coerce_bin(self, other, id_expt);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    cmp == object  -&gt;  true or false
+ *
+ * Returns true if cmp equals object numerically.
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_equal_p(VALUE self, VALUE other)
</del><ins>+nucomp_eqeq_p(VALUE self, SEL sel, VALUE other)
</ins><span class="cx"> {
</span><del>-    switch (TYPE(other)) {
-      case T_FIXNUM:
-      case T_BIGNUM:
-      case T_FLOAT:
-      case T_RATIONAL:
-        {
-            get_dat1(self);
</del><ins>+    if (k_complex_p(other)) {
+        get_dat2(self, other);
</ins><span class="cx"> 
</span><del>-            return f_boolcast(f_equal_p(dat-&gt;real, other) &amp;&amp; f_zero_p(dat-&gt;image));
-        }
-      case T_COMPLEX:
-        {
-            get_dat2(self, other);
</del><ins>+        return f_boolcast(f_eqeq_p(adat-&gt;real, bdat-&gt;real) &amp;&amp;
+                          f_eqeq_p(adat-&gt;imag, bdat-&gt;imag));
+    }
+    if (k_numeric_p(other) &amp;&amp; f_real_p(other)) {
+        get_dat1(self);
</ins><span class="cx"> 
</span><del>-            return f_boolcast(f_equal_p(adat-&gt;real, bdat-&gt;real) &amp;&amp;
-                              f_equal_p(adat-&gt;image, bdat-&gt;image));
-        }
-      default:
-        return f_equal_p(other, self);
</del><ins>+        return f_boolcast(f_eqeq_p(dat-&gt;real, other) &amp;&amp; f_zero_p(dat-&gt;imag));
</ins><span class="cx">     }
</span><ins>+    return f_eqeq_p(other, self);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/* :nodoc: */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_coerce(VALUE self, VALUE other)
</del><ins>+nucomp_coerce(VALUE self, SEL sel, VALUE other)
</ins><span class="cx"> {
</span><del>-    switch (TYPE(other)) {
-      case T_FIXNUM:
-      case T_BIGNUM:
-      case T_FLOAT:
-      case T_RATIONAL:
</del><ins>+    if (k_numeric_p(other) &amp;&amp; f_real_p(other))
</ins><span class="cx">         return rb_assoc_new(f_complex_new_bang1(CLASS_OF(self), other), self);
</span><del>-    }
</del><ins>+    if (TYPE(other) == T_COMPLEX)
+        return rb_assoc_new(other, self);
</ins><span class="cx"> 
</span><span class="cx">     rb_raise(rb_eTypeError, &quot;%s can't be coerced into %s&quot;,
</span><span class="cx">              rb_obj_classname(other), rb_obj_classname(self));
</span><span class="cx">     return Qnil;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    cmp.abs        -&gt;  real
+ *    cmp.magnitude  -&gt;  real
+ *
+ * Returns the absolute part of its polar form.
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_abs(VALUE self)
</del><ins>+nucomp_abs(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><span class="cx">     get_dat1(self);
</span><del>-    return m_hypot(dat-&gt;real, dat-&gt;image);
</del><ins>+
+    if (f_zero_p(dat-&gt;real)) {
+        VALUE a = f_abs(dat-&gt;imag);
+        if (k_float_p(dat-&gt;real) &amp;&amp; !k_float_p(dat-&gt;imag))
+            a = f_to_f(a);
+        return a;
+    }
+    if (f_zero_p(dat-&gt;imag)) {
+        VALUE a = f_abs(dat-&gt;real);
+        if (!k_float_p(dat-&gt;real) &amp;&amp; k_float_p(dat-&gt;imag))
+            a = f_to_f(a);
+        return a;
+    }
+    return m_hypot(dat-&gt;real, dat-&gt;imag);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    cmp.abs2  -&gt;  real
+ *
+ * Returns square of the absolute value.
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_abs2(VALUE self)
</del><ins>+nucomp_abs2(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><span class="cx">     get_dat1(self);
</span><span class="cx">     return f_add(f_mul(dat-&gt;real, dat-&gt;real),
</span><del>-                 f_mul(dat-&gt;image, dat-&gt;image));
</del><ins>+                 f_mul(dat-&gt;imag, dat-&gt;imag));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    cmp.arg    -&gt;  float
+ *    cmp.angle  -&gt;  float
+ *    cmp.phase  -&gt;  float
+ *
+ * Returns the angle part of its polar form.
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_arg(VALUE self)
</del><ins>+nucomp_arg(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><span class="cx">     get_dat1(self);
</span><del>-    return m_atan2_bang(dat-&gt;image, dat-&gt;real);
</del><ins>+    return m_atan2_bang(dat-&gt;imag, dat-&gt;real);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    cmp.rect         -&gt;  array
+ *    cmp.rectangular  -&gt;  array
+ *
+ * Returns an array; [cmp.real, cmp.imag].
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_polar(VALUE self)
</del><ins>+nucomp_rect(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><ins>+    get_dat1(self);
+    return rb_assoc_new(dat-&gt;real, dat-&gt;imag);
+}
+
+/*
+ * call-seq:
+ *    cmp.polar  -&gt;  array
+ *
+ * Returns an array; [cmp.abs, cmp.arg].
+ */
+static VALUE
+nucomp_polar(VALUE self, SEL sel)
+{
</ins><span class="cx">     return rb_assoc_new(f_abs(self), f_arg(self));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    cmp.conj       -&gt;  complex
+ *    cmp.conjucate  -&gt;  complex
+ *
+ * Returns the complex conjucate.
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_conjugate(VALUE self)
</del><ins>+nucomp_conj(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><span class="cx">     get_dat1(self);
</span><del>-    return f_complex_new2(CLASS_OF(self), dat-&gt;real, f_negate(dat-&gt;image));
</del><ins>+    return f_complex_new2(CLASS_OF(self), dat-&gt;real, f_negate(dat-&gt;imag));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if 0
</span><ins>+/* :nodoc: */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_real_p(VALUE self)
</del><ins>+nucomp_true(VALUE self)
</ins><span class="cx"> {
</span><del>-    return Qfalse;
</del><ins>+    return Qtrue;
</ins><span class="cx"> }
</span><ins>+#endif
</ins><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    cmp.real?  -&gt;  false
+ *
+ * Returns false.
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_complex_p(VALUE self)
</del><ins>+nucomp_false(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><del>-    return Qtrue;
</del><ins>+    return Qfalse;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#if 0
+/* :nodoc: */
</ins><span class="cx"> static VALUE
</span><span class="cx"> nucomp_exact_p(VALUE self)
</span><span class="cx"> {
</span><span class="cx">     get_dat1(self);
</span><del>-    return f_boolcast(f_exact_p(dat-&gt;real) &amp;&amp; f_exact_p(dat-&gt;image));
</del><ins>+    return f_boolcast(k_exact_p(dat-&gt;real) &amp;&amp; k_exact_p(dat-&gt;imag));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/* :nodoc: */
</ins><span class="cx"> static VALUE
</span><span class="cx"> nucomp_inexact_p(VALUE self)
</span><span class="cx"> {
</span><span class="lines">@@ -910,17 +1101,45 @@
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-extern VALUE rb_lcm(VALUE x, VALUE y);
</del><ins>+extern VALUE rb_lcm(VALUE x, SEL sel, VALUE y);
</ins><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    cmp.denominator  -&gt;  integer
+ *
+ * Returns the denominator (lcm of both denominator, real and imag).
+ *
+ * See numerator.
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_denominator(VALUE self)
</del><ins>+nucomp_denominator(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><span class="cx">     get_dat1(self);
</span><del>-    return rb_lcm(f_denominator(dat-&gt;real), f_denominator(dat-&gt;image));
</del><ins>+    return rb_lcm(f_denominator(dat-&gt;real), 0, f_denominator(dat-&gt;imag));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    cmp.numerator  -&gt;  numeric
+ *
+ * Returns the numerator.
+ *
+ * For example:
+ *
+ *        1   2       3+4i  &lt;-  numerator
+ *        - + -i  -&gt;  ----
+ *        2   3        6    &lt;-  denominator
+ *
+ *    c = Complex('1/2+2/3i')  #=&gt; ((1/2)+(2/3)*i)
+ *    n = c.numerator          #=&gt; (3+4i)
+ *    d = c.denominator        #=&gt; 6
+ *    n / d                    #=&gt; ((1/2)+(2/3)*i)
+ *    Complex(Rational(n.real, d), Rational(n.imag, d))
+ *                             #=&gt; ((1/2)+(2/3)*i)
+ * See denominator.
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_numerator(VALUE self)
</del><ins>+nucomp_numerator(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><span class="cx">     VALUE cd;
</span><span class="cx"> 
</span><span class="lines">@@ -930,17 +1149,41 @@
</span><span class="cx">     return f_complex_new2(CLASS_OF(self),
</span><span class="cx">                           f_mul(f_numerator(dat-&gt;real),
</span><span class="cx">                                 f_div(cd, f_denominator(dat-&gt;real))),
</span><del>-                          f_mul(f_numerator(dat-&gt;image),
-                                f_div(cd, f_denominator(dat-&gt;image))));
</del><ins>+                          f_mul(f_numerator(dat-&gt;imag),
+                                f_div(cd, f_denominator(dat-&gt;imag))));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/* :nodoc: */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_hash(VALUE self)
</del><ins>+nucomp_hash(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><ins>+    long v, h[2];
+    VALUE n;
+
</ins><span class="cx">     get_dat1(self);
</span><del>-    return f_xor(dat-&gt;real, dat-&gt;image);
</del><ins>+    n = rb_hash(dat-&gt;real);
+    h[0] = NUM2LONG(n);
+    n = rb_hash(dat-&gt;imag);
+    h[1] = NUM2LONG(n);
+    v = rb_memhash(h, sizeof(h));
+    return LONG2FIX(v);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/* :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-&gt;real) == CLASS_OF(bdat-&gt;real)) &amp;&amp;
+                          (CLASS_OF(adat-&gt;imag) == CLASS_OF(bdat-&gt;imag)) &amp;&amp;
+                          f_eqeq_p(self, other));
+
+    }
+    return Qfalse;
+}
+
</ins><span class="cx"> #ifndef HAVE_SIGNBIT
</span><span class="cx"> #ifdef signbit
</span><span class="cx"> #define HAVE_SIGNBIT 1
</span><span class="lines">@@ -951,94 +1194,99 @@
</span><span class="cx"> f_signbit(VALUE x)
</span><span class="cx"> {
</span><span class="cx">     switch (TYPE(x)) {
</span><del>-      case T_FLOAT:
</del><ins>+      case T_FLOAT: {
</ins><span class="cx"> #ifdef HAVE_SIGNBIT
</span><del>-        return f_boolcast(signbit(RFLOAT_VALUE(x)));
</del><ins>+        double f = RFLOAT_VALUE(x);
+        return f_boolcast(!isnan(f) &amp;&amp; signbit(f));
</ins><span class="cx"> #else
</span><del>-        {
-            char s[2];
</del><ins>+        char s[2];
+        double f = RFLOAT_VALUE(x);
</ins><span class="cx"> 
</span><del>-            (void)snprintf(s, sizeof s, &quot;%.0f&quot;, RFLOAT_VALUE(x));
-
-            return f_boolcast(s[0] == '-');
-        }
</del><ins>+        if (isnan(f)) return Qfalse;
+        (void)snprintf(s, sizeof s, &quot;%.0f&quot;, f);
+        return f_boolcast(s[0] == '-');
</ins><span class="cx"> #endif
</span><ins>+      }
</ins><span class="cx">     }
</span><span class="cx">     return f_negative_p(x);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><del>-f_tzero_p(VALUE x)
-{
-    return f_boolcast(f_zero_p(x) &amp;&amp; !f_signbit(x));
-}
-
-inline static VALUE
</del><span class="cx"> f_tpositive_p(VALUE x)
</span><span class="cx"> {
</span><span class="cx">     return f_boolcast(!f_signbit(x));
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static VALUE
</span><del>-nucomp_to_s(VALUE self)
</del><ins>+f_format(VALUE self, VALUE (*func)(VALUE))
</ins><span class="cx"> {
</span><del>-    VALUE s, rezero, impos;
</del><ins>+    VALUE s, impos;
</ins><span class="cx"> 
</span><span class="cx">     get_dat1(self);
</span><span class="cx"> 
</span><del>-    rezero = f_tzero_p(dat-&gt;real);
-    impos = f_tpositive_p(dat-&gt;image);
</del><ins>+    impos = f_tpositive_p(dat-&gt;imag);
</ins><span class="cx"> 
</span><del>-    if (rezero)
-        s = rb_str_new2(&quot;&quot;);
-    else {
-        s = f_to_s(dat-&gt;real);
-        rb_str_cat2(s, !impos ? &quot;-&quot; : &quot;+&quot;);
-    }
</del><ins>+    s = (*func)(dat-&gt;real);
+    rb_str_cat2(s, !impos ? &quot;-&quot; : &quot;+&quot;);
</ins><span class="cx"> 
</span><del>-    if (k_rational_p(dat-&gt;image) &amp;&amp;
-        !f_one_p(f_denominator(dat-&gt;image))) {
-        rb_str_cat2(s, &quot;(&quot;);
-        rb_str_concat(s, f_to_s(rezero ? dat-&gt;image : f_abs(dat-&gt;image)));
-        rb_str_cat2(s, &quot;)i&quot;);
-    }
-    else {
-        rb_str_concat(s, f_to_s(rezero ? dat-&gt;image : f_abs(dat-&gt;image)));
-        rb_str_cat2(s, &quot;i&quot;);
-    }
</del><ins>+    rb_str_concat(s, (*func)(f_abs(dat-&gt;imag)));
+    if (!rb_isdigit(RSTRING_PTR(s)[RSTRING_LEN(s) - 1]))
+        rb_str_cat2(s, &quot;*&quot;);
+    rb_str_cat2(s, &quot;i&quot;);
</ins><span class="cx"> 
</span><span class="cx">     return s;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    cmp.to_s  -&gt;  string
+ *
+ * Returns the value as a string.
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_inspect(VALUE self)
</del><ins>+nucomp_to_s(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><ins>+    return f_format(self, f_to_s);
+}
+
+/*
+ * call-seq:
+ *    cmp.inspect  -&gt;  string
+ *
+ * Returns the value as a string for inspection.
+ */
+static VALUE
+nucomp_inspect(VALUE self, SEL sel)
+{
</ins><span class="cx">     VALUE s;
</span><span class="cx"> 
</span><del>-    get_dat1(self);
-
-    s = rb_str_new2(&quot;Complex(&quot;);
-    rb_str_concat(s, f_inspect(dat-&gt;real));
-    rb_str_cat2(s, &quot;, &quot;);
-    rb_str_concat(s, f_inspect(dat-&gt;image));
</del><ins>+    s = rb_usascii_str_new2(&quot;(&quot;);
+    rb_str_concat(s, f_format(self, f_inspect));
</ins><span class="cx">     rb_str_cat2(s, &quot;)&quot;);
</span><span class="cx"> 
</span><span class="cx">     return s;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/* :nodoc: */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_marshal_dump(VALUE self)
</del><ins>+nucomp_marshal_dump(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><ins>+    VALUE a;
</ins><span class="cx">     get_dat1(self);
</span><del>-    return rb_assoc_new(dat-&gt;real, dat-&gt;image);
</del><ins>+
+    a = rb_assoc_new(dat-&gt;real, dat-&gt;imag);
+    rb_copy_generic_ivar(a, self);
+    return a;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/* :nodoc: */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_marshal_load(VALUE self, VALUE a)
</del><ins>+nucomp_marshal_load(VALUE self, SEL sel, VALUE a)
</ins><span class="cx"> {
</span><span class="cx">     get_dat1(self);
</span><del>-    dat-&gt;real = RARRAY_AT(a, 0);
-    dat-&gt;image = RARRAY_AT(a, 1);
</del><ins>+    dat-&gt;real = RARRAY_PTR(a)[0];
+    dat-&gt;imag = RARRAY_PTR(a)[1];
+    rb_copy_generic_ivar(self, a);
</ins><span class="cx">     return self;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1056,29 +1304,35 @@
</span><span class="cx">     return nucomp_s_canonicalize_internal(rb_cComplex, x, y);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static VALUE nucomp_s_convert(int argc, VALUE *argv, VALUE klass);
</del><ins>+VALUE
+rb_complex_polar(VALUE x, VALUE y)
+{
+    return f_complex_polar(rb_cComplex, x, y);
+}
</ins><span class="cx"> 
</span><ins>+static VALUE nucomp_s_convert(VALUE klass, SEL sel, int argc, VALUE *argv);
+
</ins><span class="cx"> VALUE
</span><span class="cx"> rb_Complex(VALUE x, VALUE y)
</span><span class="cx"> {
</span><span class="cx">     VALUE a[2];
</span><span class="cx">     a[0] = x;
</span><span class="cx">     a[1] = y;
</span><del>-    return nucomp_s_convert(2, a, rb_cComplex);
</del><ins>+    return nucomp_s_convert(rb_cComplex, NULL, 2, a);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    cmp.to_i  -&gt;  integer
+ *
+ * Returns the value as an integer if possible.
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_scalar_p(VALUE self)
</del><ins>+nucomp_to_i(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><del>-    return Qfalse;
-}
-
-static VALUE
-nucomp_to_i(VALUE self)
-{
</del><span class="cx">     get_dat1(self);
</span><span class="cx"> 
</span><del>-    if (k_float_p(dat-&gt;image) || !f_zero_p(dat-&gt;image)) {
</del><ins>+    if (k_inexact_p(dat-&gt;imag) || f_nonzero_p(dat-&gt;imag)) {
</ins><span class="cx">         VALUE s = f_to_s(self);
</span><span class="cx">         rb_raise(rb_eRangeError, &quot;can't convert %s into Integer&quot;,
</span><span class="cx">                  StringValuePtr(s));
</span><span class="lines">@@ -1086,12 +1340,18 @@
</span><span class="cx">     return f_to_i(dat-&gt;real);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    cmp.to_f  -&gt;  float
+ *
+ * Returns the value as a float if possible.
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_to_f(VALUE self)
</del><ins>+nucomp_to_f(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><span class="cx">     get_dat1(self);
</span><span class="cx"> 
</span><del>-    if (k_float_p(dat-&gt;image) || !f_zero_p(dat-&gt;image)) {
</del><ins>+    if (k_inexact_p(dat-&gt;imag) || f_nonzero_p(dat-&gt;imag)) {
</ins><span class="cx">         VALUE s = f_to_s(self);
</span><span class="cx">         rb_raise(rb_eRangeError, &quot;can't convert %s into Float&quot;,
</span><span class="cx">                  StringValuePtr(s));
</span><span class="lines">@@ -1099,12 +1359,18 @@
</span><span class="cx">     return f_to_f(dat-&gt;real);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    cmp.to_r  -&gt;  rational
+ *
+ * Returns the value as a rational if possible.
+ */
</ins><span class="cx"> static VALUE
</span><del>-nucomp_to_r(VALUE self)
</del><ins>+nucomp_to_r(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><span class="cx">     get_dat1(self);
</span><span class="cx"> 
</span><del>-    if (k_float_p(dat-&gt;image) || !f_zero_p(dat-&gt;image)) {
</del><ins>+    if (k_inexact_p(dat-&gt;imag) || f_nonzero_p(dat-&gt;imag)) {
</ins><span class="cx">         VALUE s = f_to_s(self);
</span><span class="cx">         rb_raise(rb_eRangeError, &quot;can't convert %s into Rational&quot;,
</span><span class="cx">                  StringValuePtr(s));
</span><span class="lines">@@ -1112,67 +1378,79 @@
</span><span class="cx">     return f_to_r(dat-&gt;real);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    nil.to_c  -&gt;  (0+0i)
+ *
+ * Returns zero as a complex.
+ */
</ins><span class="cx"> static VALUE
</span><del>-nilclass_to_c(VALUE self)
</del><ins>+nilclass_to_c(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><span class="cx">     return rb_complex_new1(INT2FIX(0));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    num.to_c  -&gt;  complex
+ *
+ * Returns the value as a complex.
+ */
</ins><span class="cx"> static VALUE
</span><del>-numeric_to_c(VALUE self)
</del><ins>+numeric_to_c(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><span class="cx">     return rb_complex_new1(self);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static VALUE comp_pat1, comp_pat2, a_slash, a_dot_and_an_e,
-    image_garbages_pat, null_string, underscores_pat, an_underscore;
</del><ins>+static VALUE comp_pat0, comp_pat1, comp_pat2, a_slash, a_dot_and_an_e,
+    null_string, underscores_pat, an_underscore;
</ins><span class="cx"> 
</span><del>-#define DIGITS &quot;(?:\\d(?:_\\d|\\d)*)&quot;
</del><ins>+#define WS &quot;\\s*&quot;
+#define DIGITS &quot;(?:[0-9](?:_[0-9]|[0-9])*)&quot;
</ins><span class="cx"> #define NUMERATOR &quot;(?:&quot; DIGITS &quot;?\\.)?&quot; DIGITS &quot;(?:[eE][-+]?&quot; DIGITS &quot;)?&quot;
</span><del>-#define DENOMINATOR &quot;[-+]?&quot; DIGITS
</del><ins>+#define DENOMINATOR DIGITS
</ins><span class="cx"> #define NUMBER &quot;[-+]?&quot; NUMERATOR &quot;(?:\\/&quot; DENOMINATOR &quot;)?&quot;
</span><span class="cx"> #define NUMBERNOS NUMERATOR &quot;(?:\\/&quot; DENOMINATOR &quot;)?&quot;
</span><del>-#define PATTERN1 &quot;\\A(&quot; NUMBER &quot;|\\(&quot; NUMBER &quot;\\))[iIjJ]&quot;
-#define PATTERN2 &quot;\\A(&quot; NUMBER &quot;)([-+](?:&quot; NUMBERNOS &quot;|\\(&quot; NUMBER &quot;\\))[iIjJ])?&quot;
</del><ins>+#define PATTERN0 &quot;\\A&quot; WS &quot;(&quot; NUMBER &quot;)@(&quot; NUMBER &quot;)&quot; WS
+#define PATTERN1 &quot;\\A&quot; WS &quot;([-+])?(&quot; NUMBER &quot;)?[iIjJ]&quot; WS
+#define PATTERN2 &quot;\\A&quot; WS &quot;(&quot; NUMBER &quot;)(([-+])(&quot; NUMBERNOS &quot;)?[iIjJ])?&quot; WS
</ins><span class="cx"> 
</span><span class="cx"> static void
</span><span class="cx"> make_patterns(void)
</span><span class="cx"> {
</span><del>-    static char comp_pat1_source[] = PATTERN1;
-    static char comp_pat2_source[] = PATTERN2;
-    static char image_garbages_pat_source[] = &quot;[+\\(\\)iIjJ]&quot;;
-    static char underscores_pat_source[] = &quot;_+&quot;;
</del><ins>+    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[] = &quot;_+&quot;;
</ins><span class="cx"> 
</span><ins>+    if (comp_pat0) return;
+
+    comp_pat0 = rb_reg_new(comp_pat0_source, sizeof comp_pat0_source - 1, 0);
+    rb_register_mark_object(comp_pat0);
+
</ins><span class="cx">     comp_pat1 = rb_reg_new(comp_pat1_source, sizeof comp_pat1_source - 1, 0);
</span><del>-    rb_global_variable(&amp;comp_pat1);
</del><ins>+    rb_register_mark_object(comp_pat1);
</ins><span class="cx"> 
</span><span class="cx">     comp_pat2 = rb_reg_new(comp_pat2_source, sizeof comp_pat2_source - 1, 0);
</span><del>-    rb_global_variable(&amp;comp_pat2);
</del><ins>+    rb_register_mark_object(comp_pat2);
</ins><span class="cx"> 
</span><del>-    a_slash = rb_str_new2(&quot;/&quot;);
-    rb_global_variable(&amp;a_slash);
</del><ins>+    a_slash = rb_usascii_str_new2(&quot;/&quot;);
+    rb_register_mark_object(a_slash);
</ins><span class="cx"> 
</span><del>-    a_dot_and_an_e = rb_str_new2(&quot;.eE&quot;);
-    rb_global_variable(&amp;a_dot_and_an_e);
</del><ins>+    a_dot_and_an_e = rb_usascii_str_new2(&quot;.eE&quot;);
+    rb_register_mark_object(a_dot_and_an_e);
</ins><span class="cx"> 
</span><del>-    image_garbages_pat = rb_reg_new(image_garbages_pat_source,
-                                    sizeof image_garbages_pat_source - 1, 0);
-    rb_global_variable(&amp;image_garbages_pat);
</del><ins>+    null_string = rb_usascii_str_new2(&quot;&quot;);
+    rb_register_mark_object(null_string);
</ins><span class="cx"> 
</span><del>-    null_string = rb_str_new2(&quot;&quot;);
-    rb_global_variable(&amp;null_string);
-
</del><span class="cx">     underscores_pat = rb_reg_new(underscores_pat_source,
</span><span class="cx">                                  sizeof underscores_pat_source - 1, 0);
</span><del>-    rb_global_variable(&amp;underscores_pat);
</del><ins>+    rb_register_mark_object(underscores_pat);
</ins><span class="cx"> 
</span><del>-    an_underscore = rb_str_new2(&quot;_&quot;);
-    rb_global_variable(&amp;an_underscore);
</del><ins>+    an_underscore = rb_usascii_str_new2(&quot;_&quot;);
+    rb_register_mark_object(an_underscore);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-#define id_strip rb_intern(&quot;strip&quot;)
-#define f_strip(x) rb_funcall(x, id_strip, 0)
-
</del><span class="cx"> #define id_match rb_intern(&quot;match&quot;)
</span><span class="cx"> #define f_match(x,y) rb_funcall(x, id_match, 1, y)
</span><span class="cx"> 
</span><span class="lines">@@ -1199,27 +1477,59 @@
</span><span class="cx"> {
</span><span class="cx">     VALUE s;
</span><span class="cx"> 
</span><del>-    s = f_strip(self);
</del><ins>+    s = self;
</ins><span class="cx"> 
</span><span class="cx">     if (RSTRING_LEN(s) == 0)
</span><span class="cx">         return rb_assoc_new(Qnil, self);
</span><span class="cx"> 
</span><span class="cx">     {
</span><span class="cx">         VALUE m, sr, si, re, r, i;
</span><ins>+        int po;
</ins><span class="cx"> 
</span><del>-        m = f_match(comp_pat1, s);
</del><ins>+        m = f_match(comp_pat0, s);
</ins><span class="cx">         if (!NIL_P(m)) {
</span><del>-            sr = Qnil;
-            si = f_aref(m, INT2FIX(1));
-            re = f_post_match(m);
</del><ins>+          sr = f_aref(m, INT2FIX(1));
+          si = f_aref(m, INT2FIX(2));
+          re = f_post_match(m);
+          po = 1;
</ins><span class="cx">         }
</span><span class="cx">         if (NIL_P(m)) {
</span><ins>+            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(&quot;&quot;);
+                {
+                    VALUE t;
+
+                    t = f_aref(m, INT2FIX(2));
+                    if (NIL_P(t))
+                        t = rb_usascii_str_new2(&quot;1&quot;);
+                    rb_str_concat(si, t);
+                }
+                re = f_post_match(m);
+                po = 0;
+            }
+        }
+        if (NIL_P(m)) {
</ins><span class="cx">             m = f_match(comp_pat2, s);
</span><span class="cx">             if (NIL_P(m))
</span><span class="cx">                 return rb_assoc_new(Qnil, self);
</span><span class="cx">             sr = f_aref(m, INT2FIX(1));
</span><del>-            si = f_aref(m, INT2FIX(2));
</del><ins>+            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(&quot;1&quot;);
+                rb_str_concat(si, t);
+            }
</ins><span class="cx">             re = f_post_match(m);
</span><ins>+            po = 0;
</ins><span class="cx">         }
</span><span class="cx">         r = INT2FIX(0);
</span><span class="cx">         i = INT2FIX(0);
</span><span class="lines">@@ -1232,7 +1542,6 @@
</span><span class="cx">                 r = f_to_i(sr);
</span><span class="cx">         }
</span><span class="cx">         if (!NIL_P(si)) {
</span><del>-            f_gsub_bang(si, image_garbages_pat, null_string);
</del><span class="cx">             if (f_include_p(si, a_slash))
</span><span class="cx">                 i = f_to_r(si);
</span><span class="cx">             else if (f_gt_p(f_count(si, a_dot_and_an_e), INT2FIX(0)))
</span><span class="lines">@@ -1240,7 +1549,10 @@
</span><span class="cx">             else
</span><span class="cx">                 i = f_to_i(si);
</span><span class="cx">         }
</span><del>-        return rb_assoc_new(rb_complex_new2(r, i), re);
</del><ins>+        if (po)
+            return rb_assoc_new(rb_complex_polar(r, i), re);
+        else
+            return rb_assoc_new(rb_complex_new2(r, i), re);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1248,36 +1560,71 @@
</span><span class="cx"> string_to_c_strict(VALUE self)
</span><span class="cx"> {
</span><span class="cx">     VALUE a = string_to_c_internal(self);
</span><del>-    if (NIL_P(RARRAY_AT(a, 0)) || RSTRING_LEN(RARRAY_AT(a, 1)) &gt; 0) {
</del><ins>+    if (NIL_P(RARRAY_PTR(a)[0]) || RSTRING_LEN(RARRAY_PTR(a)[1]) &gt; 0) {
</ins><span class="cx">         VALUE s = f_inspect(self);
</span><del>-        rb_raise(rb_eArgError, &quot;invalid value for Complex: %s&quot;,
</del><ins>+        rb_raise(rb_eArgError, &quot;invalid value for convert(): %s&quot;,
</ins><span class="cx">                  StringValuePtr(s));
</span><span class="cx">     }
</span><del>-    return RARRAY_AT(a, 0);
</del><ins>+    return RARRAY_PTR(a)[0];
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #define id_gsub rb_intern(&quot;gsub&quot;)
</span><span class="cx"> #define f_gsub(x,y,z) rb_funcall(x, id_gsub, 2, y, z)
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    str.to_c  -&gt;  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           #=&gt; (9+0i)
+ *    '2.5'.to_c         #=&gt; (2.5+0i)
+ *    '2.5/1'.to_c       #=&gt; ((5/2)+0i)
+ *    '-3/2'.to_c        #=&gt; ((-3/2)+0i)
+ *    '-i'.to_c          #=&gt; (0-1i)
+ *    '45i'.to_c         #=&gt; (0+45i)
+ *    '3-4i'.to_c        #=&gt; (3-4i)
+ *    '-4e2-4e-2i'.to_c  #=&gt; (-400.0-0.04i)
+ *    '-0.0-0.0i'.to_c   #=&gt; (-0.0-0.0i)
+ *    '1/2+3/4i'.to_c    #=&gt; ((1/2)+(3/4)*i)
+ *    'ruby'.to_c        #=&gt; (0+0i)
+ */
</ins><span class="cx"> static VALUE
</span><del>-string_to_c(VALUE self)
</del><ins>+string_to_c(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><del>-    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);
</del><ins>+    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];
</ins><span class="cx">     return rb_complex_new1(INT2FIX(0));
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static VALUE
</span><del>-nucomp_s_convert(int argc, VALUE *argv, VALUE klass)
</del><ins>+nucomp_s_convert(VALUE klass, SEL sel, int argc, VALUE *argv)
</ins><span class="cx"> {
</span><del>-    VALUE a1, a2;
</del><ins>+    VALUE a1, a2, backref;
</ins><span class="cx"> 
</span><del>-    a1 = Qnil;
-    a2 = Qnil;
-    rb_scan_args(argc, argv, &quot;02&quot;, &amp;a1, &amp;a2);
</del><ins>+    rb_scan_args(argc, argv, &quot;11&quot;, &amp;a1, &amp;a2);
</ins><span class="cx"> 
</span><ins>+    if (NIL_P(a1) || (argc == 2 &amp;&amp; NIL_P(a2)))
+        rb_raise(rb_eTypeError, &quot;can't convert nil into Complex&quot;);
+
+    backref = rb_backref_get();
+    rb_match_busy(backref);
+
</ins><span class="cx">     switch (TYPE(a1)) {
</span><span class="cx">       case T_FIXNUM:
</span><span class="cx">       case T_BIGNUM:
</span><span class="lines">@@ -1298,12 +1645,14 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    rb_backref_set(backref);
+
</ins><span class="cx">     switch (TYPE(a1)) {
</span><span class="cx">       case T_COMPLEX:
</span><span class="cx">         {
</span><span class="cx">             get_dat1(a1);
</span><span class="cx"> 
</span><del>-            if (!k_float_p(dat-&gt;image) &amp;&amp; f_zero_p(dat-&gt;image))
</del><ins>+            if (k_exact_zero_p(dat-&gt;imag))
</ins><span class="cx">                 a1 = dat-&gt;real;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -1313,235 +1662,343 @@
</span><span class="cx">         {
</span><span class="cx">             get_dat1(a2);
</span><span class="cx"> 
</span><del>-            if (!k_float_p(dat-&gt;image) &amp;&amp; f_zero_p(dat-&gt;image))
</del><ins>+            if (k_exact_zero_p(dat-&gt;imag))
</ins><span class="cx">                 a2 = dat-&gt;real;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     switch (TYPE(a1)) {
</span><span class="cx">       case T_COMPLEX:
</span><del>-        if (NIL_P(a2) || f_zero_p(a2))
</del><ins>+        if (argc == 1 || (k_exact_zero_p(a2)))
</ins><span class="cx">             return a1;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    if (argc == 1) {
+        if (k_numeric_p(a1) &amp;&amp; !f_real_p(a1))
+            return a1;
+        /* expect raise exception for consistency */
+        if (!k_numeric_p(a1))
+            return rb_convert_type(a1, T_COMPLEX, &quot;Complex&quot;, &quot;to_c&quot;);
+    }
+    else {
+        if ((k_numeric_p(a1) &amp;&amp; k_numeric_p(a2)) &amp;&amp;
+            (!f_real_p(a1) || !f_real_p(a2)))
+            return f_add(a1,
+                         f_mul(a2,
+                               f_complex_new_bang2(rb_cComplex, ZERO, ONE)));
+    }
+
</ins><span class="cx">     {
</span><span class="cx">         VALUE argv2[2];
</span><span class="cx">         argv2[0] = a1;
</span><span class="cx">         argv2[1] = a2;
</span><del>-        return nucomp_s_new(argc, argv2, klass);
</del><ins>+        return nucomp_s_new(klass, NULL, argc, argv2);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> /* --- */
</span><span class="cx"> 
</span><del>-#define id_Complex rb_intern(&quot;Complex&quot;)
-
</del><ins>+/*
+ * call-seq:
+ *    num.real  -&gt;  self
+ *
+ * Returns self.
+ */
</ins><span class="cx"> static VALUE
</span><del>-numeric_re(VALUE self)
</del><ins>+numeric_real(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><del>-    return rb_Complex1(self);
</del><ins>+    return self;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    num.imag       -&gt;  0
+ *    num.imaginary  -&gt;  0
+ *
+ * Returns zero.
+ */
</ins><span class="cx"> static VALUE
</span><del>-numeric_im(VALUE self)
</del><ins>+numeric_imag(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><del>-    return rb_Complex2(ZERO, self);
</del><ins>+    return INT2FIX(0);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    num.abs2  -&gt;  real
+ *
+ * Returns square of self.
+ */
</ins><span class="cx"> static VALUE
</span><del>-numeric_real(VALUE self)
</del><ins>+numeric_abs2(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><del>-    return self;
</del><ins>+    return f_mul(self, self);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-static VALUE
-numeric_image(VALUE self)
-{
-    return INT2FIX(0);
-}
-
</del><span class="cx"> #define id_PI rb_intern(&quot;PI&quot;)
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    num.arg    -&gt;  0 or float
+ *    num.angle  -&gt;  0 or float
+ *    num.phase  -&gt;  0 or float
+ *
+ * Returns 0 if the value is positive, pi otherwise.
+ */
</ins><span class="cx"> static VALUE
</span><del>-numeric_arg(VALUE self)
</del><ins>+numeric_arg(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><del>-    if (!f_negative_p(self))
</del><ins>+    if (f_positive_p(self))
</ins><span class="cx">         return INT2FIX(0);
</span><span class="cx">     return rb_const_get(rb_mMath, id_PI);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    num.rect  -&gt;  array
+ *
+ * Returns an array; [num, 0].
+ */
</ins><span class="cx"> static VALUE
</span><del>-numeric_polar(VALUE self)
</del><ins>+numeric_rect(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><ins>+    return rb_assoc_new(self, INT2FIX(0));
+}
+
+/*
+ * call-seq:
+ *    num.polar  -&gt;  array
+ *
+ * Returns an array; [num.abs, num.arg].
+ */
+static VALUE
+numeric_polar(VALUE self, SEL sel)
+{
</ins><span class="cx">     return rb_assoc_new(f_abs(self), f_arg(self));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    num.conj       -&gt;  self
+ *    num.conjucate  -&gt;  self
+ *
+ * Returns self.
+ */
</ins><span class="cx"> static VALUE
</span><del>-numeric_conjugate(VALUE self)
</del><ins>+numeric_conj(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><span class="cx">     return self;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    flo.arg    -&gt;  0 or float
+ *    flo.angle  -&gt;  0 or float
+ *    flo.phase  -&gt;  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)           #=&gt; (1+0i)
+ *    Complex(2, 3)        #=&gt; (2+3i)
+ *    Complex.polar(2, 3)  #=&gt; (-1.9799849932008908+0.2822400161197344i)
+ *    3.to_c               #=&gt; (3+0i)
+ *
+ * You can also create complex object from floating-point numbers or
+ * strings.
+ *
+ *    Complex(0.3)         #=&gt; (0.3+0i)
+ *    Complex('0.3-0.5i')  #=&gt; (0.3-0.5i)
+ *    Complex('2/3+3/4i')  #=&gt; ((2/3)+(3/4)*i)
+ *    Complex('1@2')       #=&gt; (-0.4161468365471424+0.9092974268256817i)
+ *
+ *    0.3.to_c             #=&gt; (0.3+0i)
+ *    '0.3-0.5i'.to_c      #=&gt; (0.3-0.5i)
+ *    '2/3+3/4i'.to_c      #=&gt; ((2/3)+(3/4)*i)
+ *    '1@2'.to_c           #=&gt; (-0.4161468365471424+0.9092974268256817i)
+ *
+ * A complex object is either an exact or an inexact number.
+ *
+ *    Complex(1, 1) / 2    #=&gt; ((1/2)+(1/2)*i)
+ *    Complex(1, 1) / 2.0  #=&gt; (0.5+0.5i)
+ */
</ins><span class="cx"> void
</span><span class="cx"> Init_Complex(void)
</span><span class="cx"> {
</span><span class="cx">     assert(fprintf(stderr, &quot;assert() is now active\n&quot;));
</span><span class="cx"> 
</span><del>-    id_Unify = rb_intern(&quot;Unify&quot;);
</del><span class="cx">     id_abs = rb_intern(&quot;abs&quot;);
</span><span class="cx">     id_abs2 = rb_intern(&quot;abs2&quot;);
</span><span class="cx">     id_arg = rb_intern(&quot;arg&quot;);
</span><del>-    id_atan2_bang = rb_intern(&quot;atan2!&quot;);
</del><span class="cx">     id_cmp = rb_intern(&quot;&lt;=&gt;&quot;);
</span><del>-    id_conjugate = rb_intern(&quot;conjugate&quot;);
</del><ins>+    id_conj = rb_intern(&quot;conj&quot;);
</ins><span class="cx">     id_convert = rb_intern(&quot;convert&quot;);
</span><del>-    id_cos = rb_intern(&quot;cos&quot;);
</del><span class="cx">     id_denominator = rb_intern(&quot;denominator&quot;);
</span><span class="cx">     id_divmod = rb_intern(&quot;divmod&quot;);
</span><del>-    id_equal_p = rb_intern(&quot;==&quot;);
-    id_exact_p = rb_intern(&quot;exact?&quot;);
-    id_exp_bang = rb_intern(&quot;exp!&quot;);
</del><ins>+    id_eqeq_p = rb_intern(&quot;==&quot;);
</ins><span class="cx">     id_expt = rb_intern(&quot;**&quot;);
</span><ins>+    id_fdiv = rb_intern(&quot;fdiv&quot;);
</ins><span class="cx">     id_floor = rb_intern(&quot;floor&quot;);
</span><del>-    id_format = rb_intern(&quot;format&quot;);
-    id_hypot = rb_intern(&quot;hypot&quot;);
</del><span class="cx">     id_idiv = rb_intern(&quot;div&quot;);
</span><ins>+    id_imag = rb_intern(&quot;imag&quot;);
</ins><span class="cx">     id_inspect = rb_intern(&quot;inspect&quot;);
</span><del>-    id_log_bang = rb_intern(&quot;log!&quot;);
</del><span class="cx">     id_negate = rb_intern(&quot;-@&quot;);
</span><del>-    id_new = rb_intern(&quot;new&quot;);
-    id_new_bang = rb_intern(&quot;new!&quot;);
</del><span class="cx">     id_numerator = rb_intern(&quot;numerator&quot;);
</span><del>-    id_polar = rb_intern(&quot;polar&quot;);
</del><span class="cx">     id_quo = rb_intern(&quot;quo&quot;);
</span><del>-    id_scalar_p = rb_intern(&quot;scalar?&quot;);
-    id_sin = rb_intern(&quot;sin&quot;);
-    id_sqrt = rb_intern(&quot;sqrt&quot;);
</del><ins>+    id_real = rb_intern(&quot;real&quot;);
+    id_real_p = rb_intern(&quot;real?&quot;);
</ins><span class="cx">     id_to_f = rb_intern(&quot;to_f&quot;);
</span><span class="cx">     id_to_i = rb_intern(&quot;to_i&quot;);
</span><span class="cx">     id_to_r = rb_intern(&quot;to_r&quot;);
</span><span class="cx">     id_to_s = rb_intern(&quot;to_s&quot;);
</span><del>-    id_truncate = rb_intern(&quot;truncate&quot;);
</del><span class="cx"> 
</span><del>-    rb_cComplex = rb_define_class(COMPLEX_NAME, rb_cNumeric);
</del><ins>+    rb_cComplex = rb_define_class(&quot;Complex&quot;, rb_cNumeric);
</ins><span class="cx"> 
</span><del>-    rb_define_alloc_func(rb_cComplex, nucomp_s_alloc);
-//    rb_funcall(rb_cComplex, rb_intern(&quot;private_class_method&quot;), 1,
-//               ID2SYM(rb_intern(&quot;allocate&quot;)));
</del><ins>+    rb_objc_define_method(*(VALUE *)rb_cComplex, &quot;alloc&quot;, nucomp_s_alloc, 0);
+    rb_undef_method(CLASS_OF(rb_cComplex), &quot;allocate&quot;);
</ins><span class="cx"> 
</span><del>-    rb_define_singleton_method(rb_cComplex, &quot;generic?&quot;, nucomp_s_generic_p, 1);
-
-    rb_define_singleton_method(rb_cComplex, &quot;new!&quot;, nucomp_s_new_bang, -1);
-//    rb_funcall(rb_cComplex, rb_intern(&quot;private_class_method&quot;), 1,
-//               ID2SYM(rb_intern(&quot;new!&quot;)));
-
-    rb_define_singleton_method(rb_cComplex, &quot;new&quot;, nucomp_s_new, -1);
-//    rb_funcall(rb_cComplex, rb_intern(&quot;private_class_method&quot;), 1,
-//               ID2SYM(rb_intern(&quot;new&quot;)));
-
</del><span class="cx"> #if 0
</span><del>-    rb_define_singleton_method(rb_cComplex, &quot;rect&quot;, nucomp_s_new, -1);
-    rb_define_singleton_method(rb_cComplex, &quot;rectangular&quot;, nucomp_s_new, -1);
</del><ins>+    rb_define_private_method(CLASS_OF(rb_cComplex), &quot;new!&quot;, nucomp_s_new_bang, -1);
+    rb_define_private_method(CLASS_OF(rb_cComplex), &quot;new&quot;, nucomp_s_new, -1);
+#else
+    rb_undef_method(CLASS_OF(rb_cComplex), &quot;new&quot;);
</ins><span class="cx"> #endif
</span><del>-    rb_define_singleton_method(rb_cComplex, &quot;polar&quot;, nucomp_s_polar, 2);
</del><span class="cx"> 
</span><del>-    rb_define_global_function(COMPLEX_NAME, nucomp_f_complex, -1);
</del><ins>+    rb_objc_define_method(*(VALUE *)rb_cComplex, &quot;rectangular&quot;, nucomp_s_new, -1);
+    rb_objc_define_method(*(VALUE *)rb_cComplex, &quot;rect&quot;, nucomp_s_new, -1);
+    rb_objc_define_method(*(VALUE *)rb_cComplex, &quot;polar&quot;, nucomp_s_polar, -1);
</ins><span class="cx"> 
</span><ins>+    rb_objc_define_method(rb_mKernel, &quot;Complex&quot;, nucomp_f_complex, -1);
+
+    rb_undef_method(rb_cComplex, &quot;%&quot;);
</ins><span class="cx">     rb_undef_method(rb_cComplex, &quot;&lt;&quot;);
</span><span class="cx">     rb_undef_method(rb_cComplex, &quot;&lt;=&quot;);
</span><span class="cx">     rb_undef_method(rb_cComplex, &quot;&lt;=&gt;&quot;);
</span><span class="cx">     rb_undef_method(rb_cComplex, &quot;&gt;&quot;);
</span><span class="cx">     rb_undef_method(rb_cComplex, &quot;&gt;=&quot;);
</span><span class="cx">     rb_undef_method(rb_cComplex, &quot;between?&quot;);
</span><ins>+    rb_undef_method(rb_cComplex, &quot;div&quot;);
</ins><span class="cx">     rb_undef_method(rb_cComplex, &quot;divmod&quot;);
</span><span class="cx">     rb_undef_method(rb_cComplex, &quot;floor&quot;);
</span><span class="cx">     rb_undef_method(rb_cComplex, &quot;ceil&quot;);
</span><span class="cx">     rb_undef_method(rb_cComplex, &quot;modulo&quot;);
</span><ins>+    rb_undef_method(rb_cComplex, &quot;remainder&quot;);
</ins><span class="cx">     rb_undef_method(rb_cComplex, &quot;round&quot;);
</span><span class="cx">     rb_undef_method(rb_cComplex, &quot;step&quot;);
</span><span class="cx">     rb_undef_method(rb_cComplex, &quot;truncate&quot;);
</span><span class="cx"> 
</span><del>-#if NUBY
</del><ins>+#if 0 /* NUBY */
</ins><span class="cx">     rb_undef_method(rb_cComplex, &quot;//&quot;);
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    rb_define_method(rb_cComplex, &quot;real&quot;, nucomp_real, 0);
-    rb_define_method(rb_cComplex, &quot;image&quot;, nucomp_image, 0);
-    rb_define_method(rb_cComplex, &quot;imag&quot;, nucomp_image, 0);
</del><ins>+    rb_objc_define_method(rb_cComplex, &quot;real&quot;, nucomp_real, 0);
+    rb_objc_define_method(rb_cComplex, &quot;imaginary&quot;, nucomp_imag, 0);
+    rb_objc_define_method(rb_cComplex, &quot;imag&quot;, nucomp_imag, 0);
</ins><span class="cx"> 
</span><del>-    rb_define_method(rb_cComplex, &quot;+&quot;, nucomp_add, 1);
-    rb_define_method(rb_cComplex, &quot;-&quot;, nucomp_sub, 1);
-    rb_define_method(rb_cComplex, &quot;*&quot;, nucomp_mul, 1);
-    rb_define_method(rb_cComplex, &quot;/&quot;, nucomp_div, 1);
-    rb_define_method(rb_cComplex, &quot;quo&quot;, nucomp_quo, 1);
-    rb_define_method(rb_cComplex, &quot;fdiv&quot;, nucomp_fdiv, 1);
-    rb_define_method(rb_cComplex, &quot;**&quot;, nucomp_expt, 1);
</del><ins>+    rb_objc_define_method(rb_cComplex, &quot;-@&quot;, nucomp_negate, 0);
+    rb_objc_define_method(rb_cComplex, &quot;+&quot;, nucomp_add, 1);
+    rb_objc_define_method(rb_cComplex, &quot;-&quot;, nucomp_sub, 1);
+    rb_objc_define_method(rb_cComplex, &quot;*&quot;, nucomp_mul, 1);
+    rb_objc_define_method(rb_cComplex, &quot;/&quot;, nucomp_div, 1);
+    rb_objc_define_method(rb_cComplex, &quot;quo&quot;, nucomp_quo, 1);
+    rb_objc_define_method(rb_cComplex, &quot;fdiv&quot;, nucomp_fdiv, 1);
+    rb_objc_define_method(rb_cComplex, &quot;**&quot;, nucomp_expt, 1);
</ins><span class="cx"> 
</span><del>-    rb_define_method(rb_cComplex, &quot;==&quot;, nucomp_equal_p, 1);
-    rb_define_method(rb_cComplex, &quot;coerce&quot;, nucomp_coerce, 1);
</del><ins>+    rb_objc_define_method(rb_cComplex, &quot;==&quot;, nucomp_eqeq_p, 1);
+    rb_objc_define_method(rb_cComplex, &quot;coerce&quot;, nucomp_coerce, 1);
</ins><span class="cx"> 
</span><del>-    rb_define_method(rb_cComplex, &quot;abs&quot;, nucomp_abs, 0);
</del><ins>+    rb_objc_define_method(rb_cComplex, &quot;abs&quot;, nucomp_abs, 0);
+    rb_objc_define_method(rb_cComplex, &quot;magnitude&quot;, nucomp_abs, 0);
+    rb_objc_define_method(rb_cComplex, &quot;abs2&quot;, nucomp_abs2, 0);
+    rb_objc_define_method(rb_cComplex, &quot;arg&quot;, nucomp_arg, 0);
+    rb_objc_define_method(rb_cComplex, &quot;angle&quot;, nucomp_arg, 0);
+    rb_objc_define_method(rb_cComplex, &quot;phase&quot;, nucomp_arg, 0);
+    rb_objc_define_method(rb_cComplex, &quot;rectangular&quot;, nucomp_rect, 0);
+    rb_objc_define_method(rb_cComplex, &quot;rect&quot;, nucomp_rect, 0);
+    rb_objc_define_method(rb_cComplex, &quot;polar&quot;, nucomp_polar, 0);
+    rb_objc_define_method(rb_cComplex, &quot;conjugate&quot;, nucomp_conj, 0);
+    rb_objc_define_method(rb_cComplex, &quot;conj&quot;, nucomp_conj, 0);
</ins><span class="cx"> #if 0
</span><del>-    rb_define_method(rb_cComplex, &quot;magnitude&quot;, nucomp_abs, 0);
</del><ins>+    rb_define_method(rb_cComplex, &quot;~&quot;, nucomp_conj, 0); /* gcc */
</ins><span class="cx"> #endif
</span><del>-    rb_define_method(rb_cComplex, &quot;abs2&quot;, nucomp_abs2, 0);
-    rb_define_method(rb_cComplex, &quot;arg&quot;, nucomp_arg, 0);
-    rb_define_method(rb_cComplex, &quot;angle&quot;, nucomp_arg, 0);
-    rb_define_method(rb_cComplex, &quot;polar&quot;, nucomp_polar, 0);
-    rb_define_method(rb_cComplex, &quot;conjugate&quot;, nucomp_conjugate, 0);
-    rb_define_method(rb_cComplex, &quot;conj&quot;, nucomp_conjugate, 0);
-#if 0
-    rb_define_method(rb_cComplex, &quot;~&quot;, nucomp_conjugate, 0); /* gcc */
-#endif
</del><span class="cx"> 
</span><ins>+    rb_objc_define_method(rb_cComplex, &quot;real?&quot;, nucomp_false, 0);
</ins><span class="cx"> #if 0
</span><del>-    rb_define_method(rb_cComplex, &quot;real?&quot;, nucomp_real_p, 0);
-    rb_define_method(rb_cComplex, &quot;complex?&quot;, nucomp_complex_p, 0);
</del><ins>+    rb_define_method(rb_cComplex, &quot;complex?&quot;, nucomp_true, 0);
</ins><span class="cx">     rb_define_method(rb_cComplex, &quot;exact?&quot;, nucomp_exact_p, 0);
</span><span class="cx">     rb_define_method(rb_cComplex, &quot;inexact?&quot;, nucomp_inexact_p, 0);
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    rb_define_method(rb_cComplex, &quot;numerator&quot;, nucomp_numerator, 0);
-    rb_define_method(rb_cComplex, &quot;denominator&quot;, nucomp_denominator, 0);
</del><ins>+    rb_objc_define_method(rb_cComplex, &quot;numerator&quot;, nucomp_numerator, 0);
+    rb_objc_define_method(rb_cComplex, &quot;denominator&quot;, nucomp_denominator, 0);
</ins><span class="cx"> 
</span><del>-    rb_define_method(rb_cComplex, &quot;hash&quot;, nucomp_hash, 0);
</del><ins>+    rb_objc_define_method(rb_cComplex, &quot;hash&quot;, nucomp_hash, 0);
+    rb_objc_define_method(rb_cComplex, &quot;eql?&quot;, nucomp_eql_p, 1);
</ins><span class="cx"> 
</span><del>-    rb_define_method(rb_cComplex, &quot;to_s&quot;, nucomp_to_s, 0);
-    rb_define_method(rb_cComplex, &quot;inspect&quot;, nucomp_inspect, 0);
</del><ins>+    rb_objc_define_method(rb_cComplex, &quot;to_s&quot;, nucomp_to_s, 0);
+    rb_objc_define_method(rb_cComplex, &quot;inspect&quot;, nucomp_inspect, 0);
</ins><span class="cx"> 
</span><del>-    rb_define_method(rb_cComplex, &quot;marshal_dump&quot;, nucomp_marshal_dump, 0);
-    rb_define_method(rb_cComplex, &quot;marshal_load&quot;, nucomp_marshal_load, 1);
</del><ins>+    rb_objc_define_method(rb_cComplex, &quot;marshal_dump&quot;, nucomp_marshal_dump, 0);
+    rb_objc_define_method(rb_cComplex, &quot;marshal_load&quot;, nucomp_marshal_load, 1);
</ins><span class="cx"> 
</span><del>-    /* --- */
</del><ins>+    /* objc_--- */
</ins><span class="cx"> 
</span><del>-    rb_define_method(rb_cComplex, &quot;scalar?&quot;, nucomp_scalar_p, 0);
-    rb_define_method(rb_cComplex, &quot;to_i&quot;, nucomp_to_i, 0);
-    rb_define_method(rb_cComplex, &quot;to_f&quot;, nucomp_to_f, 0);
-    rb_define_method(rb_cComplex, &quot;to_r&quot;, nucomp_to_r, 0);
-    rb_define_method(rb_cNilClass, &quot;to_c&quot;, nilclass_to_c, 0);
-    rb_define_method(rb_cNumeric, &quot;to_c&quot;, numeric_to_c, 0);
</del><ins>+    rb_objc_define_method(rb_cComplex, &quot;to_i&quot;, nucomp_to_i, 0);
+    rb_objc_define_method(rb_cComplex, &quot;to_f&quot;, nucomp_to_f, 0);
+    rb_objc_define_method(rb_cComplex, &quot;to_r&quot;, nucomp_to_r, 0);
+    rb_objc_define_method(rb_cNilClass, &quot;to_c&quot;, nilclass_to_c, 0);
+    rb_objc_define_method(rb_cNumeric, &quot;to_c&quot;, numeric_to_c, 0);
</ins><span class="cx"> 
</span><span class="cx">     make_patterns();
</span><span class="cx"> 
</span><del>-    rb_define_method(rb_cString, &quot;to_c&quot;, string_to_c, 0);
</del><ins>+    rb_objc_define_method(rb_cString, &quot;to_c&quot;, string_to_c, 0);
</ins><span class="cx"> 
</span><del>-    rb_define_singleton_method(rb_cComplex, &quot;convert&quot;, nucomp_s_convert, -1);
-//    rb_funcall(rb_cComplex, rb_intern(&quot;private_class_method&quot;), 1,
-//               ID2SYM(rb_intern(&quot;convert&quot;)));
</del><ins>+    rb_objc_define_method(*(VALUE *)rb_cComplex, &quot;convert&quot;, nucomp_s_convert, -1);
+//    rb_define_private_method(CLASS_OF(rb_cComplex), &quot;convert&quot;, nucomp_s_convert, -1);
</ins><span class="cx"> 
</span><span class="cx">     /* --- */
</span><span class="cx"> 
</span><del>-    rb_define_method(rb_cNumeric, &quot;re&quot;, numeric_re, 0);
-    rb_define_method(rb_cNumeric, &quot;im&quot;, numeric_im, 0);
-    rb_define_method(rb_cNumeric, &quot;real&quot;, numeric_real, 0);
-    rb_define_method(rb_cNumeric, &quot;image&quot;, numeric_image, 0);
-    rb_define_method(rb_cNumeric, &quot;imag&quot;, numeric_image, 0);
-    rb_define_method(rb_cNumeric, &quot;arg&quot;, numeric_arg, 0);
-    rb_define_method(rb_cNumeric, &quot;angle&quot;, numeric_arg, 0);
-    rb_define_method(rb_cNumeric, &quot;polar&quot;, numeric_polar, 0);
-    rb_define_method(rb_cNumeric, &quot;conjugate&quot;, numeric_conjugate, 0);
-    rb_define_method(rb_cNumeric, &quot;conj&quot;, numeric_conjugate, 0);
</del><ins>+    rb_objc_define_method(rb_cNumeric, &quot;real&quot;, numeric_real, 0);
+    rb_objc_define_method(rb_cNumeric, &quot;imaginary&quot;, numeric_imag, 0);
+    rb_objc_define_method(rb_cNumeric, &quot;imag&quot;, numeric_imag, 0);
+    rb_objc_define_method(rb_cNumeric, &quot;abs2&quot;, numeric_abs2, 0);
+    rb_objc_define_method(rb_cNumeric, &quot;arg&quot;, numeric_arg, 0);
+    rb_objc_define_method(rb_cNumeric, &quot;angle&quot;, numeric_arg, 0);
+    rb_objc_define_method(rb_cNumeric, &quot;phase&quot;, numeric_arg, 0);
+    rb_objc_define_method(rb_cNumeric, &quot;rectangular&quot;, numeric_rect, 0);
+    rb_objc_define_method(rb_cNumeric, &quot;rect&quot;, numeric_rect, 0);
+    rb_objc_define_method(rb_cNumeric, &quot;polar&quot;, numeric_polar, 0);
+    rb_objc_define_method(rb_cNumeric, &quot;conjugate&quot;, numeric_conj, 0);
+    rb_objc_define_method(rb_cNumeric, &quot;conj&quot;, numeric_conj, 0);
</ins><span class="cx"> 
</span><ins>+    rb_objc_define_method(rb_cFloat, &quot;arg&quot;, float_arg, 0);
+    rb_objc_define_method(rb_cFloat, &quot;angle&quot;, float_arg, 0);
+    rb_objc_define_method(rb_cFloat, &quot;phase&quot;, float_arg, 0);
+
</ins><span class="cx">     rb_define_const(rb_cComplex, &quot;I&quot;,
</span><span class="cx">                     f_complex_new_bang2(rb_cComplex, ZERO, ONE));
</span><span class="cx"> }
</span><ins>+
+/*
+Local variables:
+c-file-style: &quot;ruby&quot;
+End:
+*/
</ins></span></pre></div>
<a id="MacRubybranchesexperimentalincluderubyrubyh"></a>
<div class="modfile"><h4>Modified: MacRuby/branches/experimental/include/ruby/ruby.h (2116 => 2117)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -669,7 +669,7 @@
</span><span class="cx"> struct RComplex {
</span><span class="cx">     struct RBasic basic;
</span><span class="cx">     VALUE real;
</span><del>-    VALUE image;
</del><ins>+    VALUE imag;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> struct RData {
</span></span></pre></div>
<a id="MacRubybranchesexperimentalnumericc"></a>
<div class="modfile"><h4>Modified: MacRuby/branches/experimental/numeric.c (2116 => 2117)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -405,7 +405,9 @@
</span><span class="cx"> static VALUE
</span><span class="cx"> num_modulo(VALUE x, SEL sel, VALUE y)
</span><span class="cx"> {
</span><del>-    return rb_funcall(x, '%', 1, y);
</del><ins>+      return rb_funcall(x, '-', 1,
+              rb_funcall(y, '*', 1,
+              rb_funcall(x, rb_intern(&quot;div&quot;), 1, y)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> /*
</span><span class="lines">@@ -437,6 +439,20 @@
</span><span class="cx"> 
</span><span class="cx"> /*
</span><span class="cx">  *  call-seq:
</span><ins>+ *     num.real?  -&gt;  true or false
+ *
+ *  Returns &lt;code&gt;true&lt;/code&gt; if &lt;i&gt;num&lt;/i&gt; is a &lt;code&gt;Real&lt;/code&gt;
+ *  (i.e. non &lt;code&gt;Complex&lt;/code&gt;).
+ */
+
+static VALUE
+num_real_p(VALUE num, SEL sel)
+{
+    return Qtrue;
+}
+
+/*
+ *  call-seq:
</ins><span class="cx">  *     num.scalar? -&gt; true or false
</span><span class="cx">  *
</span><span class="cx">  *  Returns &lt;code&gt;true&lt;/code&gt; if &lt;i&gt;num&lt;/i&gt; is an &lt;code&gt;Scalar&lt;/code&gt;
</span><span class="lines">@@ -3267,11 +3283,13 @@
</span><span class="cx">     rb_objc_define_method(rb_cNumeric, &quot;fdiv&quot;, num_fdiv, 1);
</span><span class="cx">     rb_objc_define_method(rb_cNumeric, &quot;div&quot;, num_div, 1);
</span><span class="cx">     rb_objc_define_method(rb_cNumeric, &quot;divmod&quot;, num_divmod, 1);
</span><ins>+    rb_objc_define_method(rb_cNumeric, &quot;%&quot;, num_modulo, 1);
</ins><span class="cx">     rb_objc_define_method(rb_cNumeric, &quot;modulo&quot;, num_modulo, 1);
</span><span class="cx">     rb_objc_define_method(rb_cNumeric, &quot;remainder&quot;, num_remainder, 1);
</span><span class="cx">     rb_objc_define_method(rb_cNumeric, &quot;abs&quot;, num_abs, 0);
</span><span class="cx">     rb_objc_define_method(rb_cNumeric, &quot;to_int&quot;, num_to_int, 0);
</span><del>-
</del><ins>+    
+    rb_objc_define_method(rb_cNumeric, &quot;real?&quot;, num_real_p, 0);
</ins><span class="cx">     rb_objc_define_method(rb_cNumeric, &quot;scalar?&quot;, num_scalar_p, 0);
</span><span class="cx">     rb_objc_define_method(rb_cNumeric, &quot;integer?&quot;, num_int_p, 0);
</span><span class="cx">     rb_objc_define_method(rb_cNumeric, &quot;zero?&quot;, num_zero_p, 0);
</span></span></pre></div>
<a id="MacRubybranchesexperimentalrationalc"></a>
<div class="modfile"><h4>Modified: MacRuby/branches/experimental/rational.c (2116 => 2117)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>-  rational.c: Coded by Tadayoshi Funaba 2008
</del><ins>+  rational.c: Coded by Tadayoshi Funaba 2008,2009
</ins><span class="cx"> 
</span><span class="cx">   This implementation is based on Keiju Ishitsuka's Rational library
</span><span class="cx">   which is written in ruby.
</span><span class="lines">@@ -8,23 +8,24 @@
</span><span class="cx"> #include &quot;ruby.h&quot;
</span><span class="cx"> #include &lt;math.h&gt;
</span><span class="cx"> #include &lt;float.h&gt;
</span><ins>+#include &quot;ruby/re.h&quot;
</ins><span class="cx"> 
</span><ins>+#ifdef HAVE_IEEEFP_H
+#include &lt;ieeefp.h&gt;
+#endif
+
</ins><span class="cx"> #define NDEBUG
</span><span class="cx"> #include &lt;assert.h&gt;
</span><span class="cx"> 
</span><del>-#ifndef RATIONAL_NAME
-#define RATIONAL_NAME &quot;Rational&quot;
-#endif
-
</del><span class="cx"> #define ZERO INT2FIX(0)
</span><span class="cx"> #define ONE INT2FIX(1)
</span><span class="cx"> #define TWO INT2FIX(2)
</span><span class="cx"> 
</span><span class="cx"> VALUE rb_cRational;
</span><span class="cx"> 
</span><del>-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;
</del><ins>+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;
</ins><span class="cx"> 
</span><span class="cx"> #define f_boolcast(x) ((x) ? Qtrue : Qfalse)
</span><span class="cx"> 
</span><span class="lines">@@ -52,72 +53,49 @@
</span><span class="cx"> inline static VALUE
</span><span class="cx"> f_add(VALUE x, VALUE y)
</span><span class="cx"> {
</span><del>-    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;
</del><ins>+    if (FIXNUM_P(y) &amp;&amp; FIX2LONG(y) == 0)
+        return x;
+    else if (FIXNUM_P(x) &amp;&amp; FIX2LONG(x) == 0)
+        return y;
+    return rb_funcall(x, '+', 1, y);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><span class="cx"> f_cmp(VALUE x, VALUE y)
</span><span class="cx"> {
</span><del>-    VALUE r;
</del><span class="cx">     if (FIXNUM_P(x) &amp;&amp; FIXNUM_P(y)) {
</span><span class="cx">         long c = FIX2LONG(x) - FIX2LONG(y);
</span><span class="cx">         if (c &gt; 0)
</span><span class="cx">             c = 1;
</span><span class="cx">         else if (c &lt; 0)
</span><span class="cx">             c = -1;
</span><del>-        r = INT2FIX(c);
</del><ins>+        return INT2FIX(c);
</ins><span class="cx">     }
</span><del>-    else
-        r = rb_funcall(x, id_cmp, 1, y);
-    return r;
</del><ins>+    return rb_funcall(x, id_cmp, 1, y);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><span class="cx"> f_div(VALUE x, VALUE y)
</span><span class="cx"> {
</span><del>-    VALUE r;
</del><span class="cx">     if (FIXNUM_P(y) &amp;&amp; FIX2LONG(y) == 1)
</span><del>-        r = x;
-    else
-        r = rb_funcall(x, '/', 1, y);
-    return r;
</del><ins>+        return x;
+    return rb_funcall(x, '/', 1, y);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><span class="cx"> f_gt_p(VALUE x, VALUE y)
</span><span class="cx"> {
</span><del>-    VALUE r;
</del><span class="cx">     if (FIXNUM_P(x) &amp;&amp; FIXNUM_P(y))
</span><del>-        r = f_boolcast(FIX2LONG(x) &gt; FIX2LONG(y));
-    else
-        r = rb_funcall(x, '&gt;', 1, y);
-    return r;
</del><ins>+        return f_boolcast(FIX2LONG(x) &gt; FIX2LONG(y));
+    return rb_funcall(x, '&gt;', 1, y);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><span class="cx"> f_lt_p(VALUE x, VALUE y)
</span><span class="cx"> {
</span><del>-    VALUE r;
</del><span class="cx">     if (FIXNUM_P(x) &amp;&amp; FIXNUM_P(y))
</span><del>-        r = f_boolcast(FIX2LONG(x) &lt; FIX2LONG(y));
-    else
-        r = rb_funcall(x, '&lt;', 1, y);
-    return r;
</del><ins>+        return f_boolcast(FIX2LONG(x) &lt; FIX2LONG(y));
+    return rb_funcall(x, '&lt;', 1, y);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> binop(mod, '%')
</span><span class="lines">@@ -125,58 +103,39 @@
</span><span class="cx"> inline static VALUE
</span><span class="cx"> f_mul(VALUE x, VALUE y)
</span><span class="cx"> {
</span><del>-    VALUE r;
</del><span class="cx">     if (FIXNUM_P(y)) {
</span><del>-        long _iy = FIX2LONG(y);
-        if (_iy == 0) {
-            if (TYPE(x) == T_FLOAT)
-                r = rb_float_new(0.0);
-            else
-                r = ZERO;
</del><ins>+        long iy = FIX2LONG(y);
+        if (iy == 0) {
+            if (FIXNUM_P(x) || TYPE(x) == T_BIGNUM)
+                return ZERO;
</ins><span class="cx">         }
</span><del>-        else if (_iy == 1)
-            r = x;
-        else
-            r = rb_funcall(x, '*', 1, y);
</del><ins>+        else if (iy == 1)
+            return x;
</ins><span class="cx">     }
</span><span class="cx">     else if (FIXNUM_P(x)) {
</span><del>-        long _ix = FIX2LONG(x);
-        if (_ix == 0) {
-            if (TYPE(y) == T_FLOAT)
-                r = rb_float_new(0.0);
-            else
-                r = ZERO;
</del><ins>+        long ix = FIX2LONG(x);
+        if (ix == 0) {
+            if (FIXNUM_P(y) || TYPE(y) == T_BIGNUM)
+                return ZERO;
</ins><span class="cx">         }
</span><del>-        else if (_ix == 1)
-            r = y;
-        else
-            r = rb_funcall(x, '*', 1, y);
</del><ins>+        else if (ix == 1)
+            return y;
</ins><span class="cx">     }
</span><del>-    else
-        r = rb_funcall(x, '*', 1, y);
-    return r;
</del><ins>+    return rb_funcall(x, '*', 1, y);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><span class="cx"> f_sub(VALUE x, VALUE y)
</span><span class="cx"> {
</span><del>-    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;
</del><ins>+    if (FIXNUM_P(y) &amp;&amp; FIX2LONG(y) == 0)
+        return x;
+    return rb_funcall(x, '-', 1, y);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-binop(xor, '^')
-
</del><span class="cx"> fun1(abs)
</span><span class="cx"> fun1(floor)
</span><span class="cx"> fun1(inspect)
</span><ins>+fun1(integer_p)
</ins><span class="cx"> fun1(negate)
</span><span class="cx"> fun1(to_f)
</span><span class="cx"> fun1(to_i)
</span><span class="lines">@@ -184,50 +143,65 @@
</span><span class="cx"> fun1(truncate)
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><del>-f_equal_p(VALUE x, VALUE y)
</del><ins>+f_eqeq_p(VALUE x, VALUE y)
</ins><span class="cx"> {
</span><del>-    VALUE r;
</del><span class="cx">     if (FIXNUM_P(x) &amp;&amp; FIXNUM_P(y))
</span><del>-        r = f_boolcast(FIX2LONG(x) == FIX2LONG(y));
-    else
-        r = rb_funcall(x, id_equal_p, 1, y);
-    return r;
</del><ins>+        return f_boolcast(FIX2LONG(x) == FIX2LONG(y));
+    return rb_funcall(x, id_eqeq_p, 1, y);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> fun2(expt)
</span><ins>+fun2(fdiv)
</ins><span class="cx"> fun2(idiv)
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><span class="cx"> f_negative_p(VALUE x)
</span><span class="cx"> {
</span><del>-    VALUE r;
</del><span class="cx">     if (FIXNUM_P(x))
</span><del>-        r = f_boolcast(FIX2LONG(x) &lt; 0);
-    else
-        r = rb_funcall(x, '&lt;', 1, ZERO);
-    return r;
</del><ins>+        return f_boolcast(FIX2LONG(x) &lt; 0);
+    return rb_funcall(x, '&lt;', 1, ZERO);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#define f_positive_p(x) (!f_negative_p(x))
+
</ins><span class="cx"> inline static VALUE
</span><span class="cx"> f_zero_p(VALUE x)
</span><span class="cx"> {
</span><del>-    VALUE r;
-    if (FIXNUM_P(x))
-        r = f_boolcast(FIX2LONG(x) == 0);
-    else
-        r = rb_funcall(x, id_equal_p, 1, ZERO);
-    return r;
</del><ins>+    switch (TYPE(x)) {
+      case T_FIXNUM:
+        return f_boolcast(FIX2LONG(x) == 0);
+      case T_BIGNUM:
+        return Qfalse;
+      case T_RATIONAL:
+      {
+          VALUE num = RRATIONAL(x)-&gt;num;
+
+          return f_boolcast(FIXNUM_P(num) &amp;&amp; FIX2LONG(num) == 0);
+      }
+    }
+    return rb_funcall(x, id_eqeq_p, 1, ZERO);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#define f_nonzero_p(x) (!f_zero_p(x))
+
</ins><span class="cx"> inline static VALUE
</span><span class="cx"> f_one_p(VALUE x)
</span><span class="cx"> {
</span><del>-    VALUE r;
-    if (FIXNUM_P(x))
-        r = f_boolcast(FIX2LONG(x) == 1);
-    else
-        r = rb_funcall(x, id_equal_p, 1, ONE);
-    return r;
</del><ins>+    switch (TYPE(x)) {
+      case T_FIXNUM:
+        return f_boolcast(FIX2LONG(x) == 1);
+      case T_BIGNUM:
+        return Qfalse;
+      case T_RATIONAL:
+      {
+          VALUE num = RRATIONAL(x)-&gt;num;
+          VALUE den = RRATIONAL(x)-&gt;den;
+
+          return f_boolcast(FIXNUM_P(num) &amp;&amp; FIX2LONG(num) == 1 &amp;&amp;
+                            FIXNUM_P(den) &amp;&amp; FIX2LONG(den) == 1);
+      }
+    }
+    return rb_funcall(x, id_eqeq_p, 1, ONE);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><span class="lines">@@ -260,6 +234,12 @@
</span><span class="cx">     return f_kind_of_p(x, rb_cRational);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#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) &amp;&amp; f_zero_p(x))
+#define k_exact_one_p(x) (k_exact_p(x) &amp;&amp; f_one_p(x))
+
</ins><span class="cx"> #ifndef NDEBUG
</span><span class="cx"> #define f_gcd f_gcd_orig
</span><span class="cx"> #endif
</span><span class="lines">@@ -267,8 +247,6 @@
</span><span class="cx"> inline static long
</span><span class="cx"> i_gcd(long x, long y)
</span><span class="cx"> {
</span><del>-    long b;
-
</del><span class="cx">     if (x &lt; 0)
</span><span class="cx">         x = -x;
</span><span class="cx">     if (y &lt; 0)
</span><span class="lines">@@ -279,32 +257,12 @@
</span><span class="cx">     if (y == 0)
</span><span class="cx">         return x;
</span><span class="cx"> 
</span><del>-    b = 0;
-    while ((x &amp; 1) == 0 &amp;&amp; (y &amp; 1) == 0) {
-        b += 1;
-        x &gt;&gt;= 1;
-        y &gt;&gt;= 1;
</del><ins>+    while (x &gt; 0) {
+        long t = x;
+        x = y % x;
+        y = t;
</ins><span class="cx">     }
</span><del>-
-    while ((x &amp; 1) == 0)
-        x &gt;&gt;= 1;
-
-    while ((y &amp; 1) == 0)
-        y &gt;&gt;= 1;
-
-    while (x != y) {
-        if (y &gt; x) {
-            long t;
-            t = x;
-            x = y;
-            y = t;
-        }
-        x -= y;
-        while ((x &amp; 1) == 0)
-            x &gt;&gt;= 1;
-    }
-
-    return x &lt;&lt; b;
</del><ins>+    return y;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><span class="lines">@@ -346,7 +304,7 @@
</span><span class="cx"> f_gcd(VALUE x, VALUE y)
</span><span class="cx"> {
</span><span class="cx">     VALUE r = f_gcd_orig(x, y);
</span><del>-    if (!f_zero_p(r)) {
</del><ins>+    if (f_nonzero_p(r)) {
</ins><span class="cx">         assert(f_zero_p(f_mod(x, r)));
</span><span class="cx">         assert(f_zero_p(f_mod(y, r)));
</span><span class="cx">     }
</span><span class="lines">@@ -359,8 +317,7 @@
</span><span class="cx"> {
</span><span class="cx">     if (f_zero_p(x) || f_zero_p(y))
</span><span class="cx">         return ZERO;
</span><del>-    else
-        return f_abs(f_mul(f_div(x, f_gcd(x, y)), y));
</del><ins>+    return f_abs(f_mul(f_div(x, f_gcd(x, y)), y));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #define get_dat1(x) \
</span><span class="lines">@@ -385,11 +342,14 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static VALUE
</span><del>-nurat_s_alloc(VALUE klass)
</del><ins>+nurat_s_alloc(VALUE klass, SEL sel)
</ins><span class="cx"> {
</span><span class="cx">     return nurat_s_new_internal(klass, ZERO, ONE);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#define rb_raise_zerodiv() rb_raise(rb_eZeroDivError, &quot;divided by 0&quot;)
+
+#if 0
</ins><span class="cx"> static VALUE
</span><span class="cx"> nurat_s_new_bang(int argc, VALUE *argv, VALUE klass)
</span><span class="cx"> {
</span><span class="lines">@@ -413,7 +373,7 @@
</span><span class="cx">             den = f_negate(den);
</span><span class="cx">             break;
</span><span class="cx">           case 0:
</span><del>-            rb_raise(rb_eZeroDivError, &quot;devided by zero&quot;);
</del><ins>+            rb_raise_zerodiv();
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         break;
</span><span class="lines">@@ -421,6 +381,7 @@
</span><span class="cx"> 
</span><span class="cx">     return nurat_s_new_internal(klass, num, den);
</span><span class="cx"> }
</span><ins>+#endif
</ins><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><span class="cx"> f_rational_new_bang1(VALUE klass, VALUE x)
</span><span class="lines">@@ -431,13 +392,25 @@
</span><span class="cx"> inline static VALUE
</span><span class="cx"> f_rational_new_bang2(VALUE klass, VALUE x, VALUE y)
</span><span class="cx"> {
</span><del>-    assert(!f_negative_p(y));
-    assert(!f_zero_p(y));
</del><ins>+    assert(f_positive_p(y));
+    assert(f_nonzero_p(y));
</ins><span class="cx">     return nurat_s_new_internal(klass, x, y);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-#define f_unify_p(klass) rb_const_defined(klass, id_Unify)
</del><ins>+#ifdef CANONICALIZATION_FOR_MATHN
+#define CANON
+#endif
</ins><span class="cx"> 
</span><ins>+#ifdef CANON
+static int canonicalization = 0;
+
+void
+nurat_canonicalization(int f)
+{
+    canonicalization = f;
+}
+#endif
+
</ins><span class="cx"> inline static void
</span><span class="cx"> nurat_int_check(VALUE num)
</span><span class="cx"> {
</span><span class="lines">@@ -446,11 +419,21 @@
</span><span class="cx">       case T_BIGNUM:
</span><span class="cx">         break;
</span><span class="cx">       default:
</span><del>-        rb_raise(rb_eArgError, &quot;not an integer&quot;);
</del><ins>+        if (!k_numeric_p(num) || !f_integer_p(num))
+            rb_raise(rb_eArgError, &quot;not an integer&quot;);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><ins>+nurat_int_value(VALUE num)
+{
+    nurat_int_check(num);
+    if (!k_integer_p(num))
+        num = f_to_i(num);
+    return num;
+}
+
+inline static VALUE
</ins><span class="cx"> nurat_s_canonicalize_internal(VALUE klass, VALUE num, VALUE den)
</span><span class="cx"> {
</span><span class="cx">     VALUE gcd;
</span><span class="lines">@@ -461,7 +444,7 @@
</span><span class="cx">         den = f_negate(den);
</span><span class="cx">         break;
</span><span class="cx">       case 0:
</span><del>-        rb_raise(rb_eZeroDivError, &quot;devided by zero&quot;);
</del><ins>+        rb_raise_zerodiv();
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -469,10 +452,11 @@
</span><span class="cx">     num = f_idiv(num, gcd);
</span><span class="cx">     den = f_idiv(den, gcd);
</span><span class="cx"> 
</span><del>-    if (f_one_p(den) &amp;&amp; f_unify_p(klass))
</del><ins>+#ifdef CANON
+    if (f_one_p(den) &amp;&amp; canonicalization)
</ins><span class="cx">         return num;
</span><del>-    else
-        return nurat_s_new_internal(klass, num, den);
</del><ins>+#endif
+    return nurat_s_new_internal(klass, num, den);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline static VALUE
</span><span class="lines">@@ -484,53 +468,36 @@
</span><span class="cx">         den = f_negate(den);
</span><span class="cx">         break;
</span><span class="cx">       case 0:
</span><del>-        rb_raise(rb_eZeroDivError, &quot;devided by zero&quot;);
</del><ins>+        rb_raise_zerodiv();
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (f_equal_p(den, ONE) &amp;&amp; f_unify_p(klass))
</del><ins>+#ifdef CANON
+    if (f_one_p(den) &amp;&amp; canonicalization)
</ins><span class="cx">         return num;
</span><del>-    else
-        return nurat_s_new_internal(klass, num, den);
</del><ins>+#endif
+    return nurat_s_new_internal(klass, num, den);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-#if 0
</del><span class="cx"> static VALUE
</span><del>-nurat_s_canonicalize(int argc, VALUE *argv, VALUE klass)
</del><ins>+nurat_s_new(int argc, VALUE *argv, VALUE klass)
</ins><span class="cx"> {
</span><span class="cx">     VALUE num, den;
</span><span class="cx"> 
</span><del>-    if (rb_scan_args(argc, argv, &quot;11&quot;, &amp;num, &amp;den) == 1) {
</del><ins>+    switch (rb_scan_args(argc, argv, &quot;11&quot;, &amp;num, &amp;den)) {
+      case 1:
+        num = nurat_int_value(num);
</ins><span class="cx">         den = ONE;
</span><ins>+        break;
+      default:
+        num = nurat_int_value(num);
+        den = nurat_int_value(den);
+        break;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    nurat_int_check(num);
-    nurat_int_check(den);
-
</del><span class="cx">     return nurat_s_canonicalize_internal(klass, num, den);
</span><span class="cx"> }
</span><del>-#endif
</del><span class="cx"> 
</span><del>-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, &quot;11&quot;, &amp;num, &amp;den) == 1) {
-        den = ONE;
-    }
-    return nurat_s_new(klass, num, den);
-}
-
</del><span class="cx"> inline static VALUE
</span><span class="cx"> f_rational_new1(VALUE klass, VALUE x)
</span><span class="cx"> {
</span><span class="lines">@@ -561,21 +528,54 @@
</span><span class="cx">     return nurat_s_canonicalize_internal_no_reduce(klass, x, y);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    Rational(x[, y])  -&gt;  numeric
+ *
+ * Returns x/y;
+ */
</ins><span class="cx"> static VALUE
</span><del>-nurat_f_rational(int argc, VALUE *argv, VALUE klass)
</del><ins>+nurat_f_rational(VALUE klass, SEL sel, int argc, VALUE *argv)
</ins><span class="cx"> {
</span><span class="cx">     return rb_funcall2(rb_cRational, id_convert, argc, argv);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    rat.numerator  -&gt;  integer
+ *
+ * Returns the numerator.
+ *
+ * For example:
+ *
+ *    Rational(7).numerator        #=&gt; 7
+ *    Rational(7, 1).numerator     #=&gt; 7
+ *    Rational(9, -4).numerator    #=&gt; -9
+ *    Rational(-2, -10).numerator  #=&gt; 1
+ */
</ins><span class="cx"> static VALUE
</span><del>-nurat_numerator(VALUE self)
</del><ins>+nurat_numerator(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><span class="cx">     get_dat1(self);
</span><span class="cx">     return dat-&gt;num;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    rat.denominator  -&gt;  integer
+ *
+ * Returns the denominator (always positive).
+ *
+ * For example:
+ *
+ *    Rational(7).denominator             #=&gt; 1
+ *    Rational(7, 1).denominator          #=&gt; 1
+ *    Rational(9, -4).denominator         #=&gt; 4
+ *    Rational(-2, -10).denominator       #=&gt; 5
+ *    rat.numerator.gcd(rat.denominator)  #=&gt; 1
+ */
</ins><span class="cx"> static VALUE
</span><del>-nurat_denominator(VALUE self)
</del><ins>+nurat_denominator(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><span class="cx">     get_dat1(self);
</span><span class="cx">     return dat-&gt;den;
</span><span class="lines">@@ -612,7 +612,7 @@
</span><span class="cx"> f_imul(long x, long y)
</span><span class="cx"> {
</span><span class="cx">     VALUE r = f_imul_orig(x, y);
</span><del>-    assert(f_equal_p(r, f_mul(LONG2NUM(x), LONG2NUM(y))));
</del><ins>+    assert(f_eqeq_p(r, f_mul(LONG2NUM(x), LONG2NUM(y))));
</ins><span class="cx">     return r;
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="lines">@@ -666,8 +666,22 @@
</span><span class="cx">     return f_rational_new_no_reduce2(CLASS_OF(self), num, den);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    rat + numeric  -&gt;  numeric_result
+ *
+ * Performs addition.
+ *
+ * For example:
+ *
+ *    Rational(2, 3)  + Rational(2, 3)   #=&gt; (4/3)
+ *    Rational(900)   + Rational(1)      #=&gt; (900/1)
+ *    Rational(-2, 9) + Rational(-9, 2)  #=&gt; (-85/18)
+ *    Rational(9, 8)  + 4                #=&gt; (41/8)
+ *    Rational(20, 9) + 9.8              #=&gt; 12.022222222222222
+ */
</ins><span class="cx"> static VALUE
</span><del>-nurat_add(VALUE self, VALUE other)
</del><ins>+nurat_add(VALUE self, SEL sel, VALUE other)
</ins><span class="cx"> {
</span><span class="cx">     switch (TYPE(other)) {
</span><span class="cx">       case T_FIXNUM:
</span><span class="lines">@@ -694,8 +708,22 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    rat - numeric  -&gt;  numeric_result
+ *
+ * Performs subtraction.
+ *
+ * For example:
+ *
+ *    Rational(2, 3)  - Rational(2, 3)   #=&gt; (0/1)
+ *    Rational(900)   - Rational(1)      #=&gt; (899/1)
+ *    Rational(-2, 9) - Rational(-9, 2)  #=&gt; (77/18)
+ *    Rational(9, 8)  - 4                #=&gt; (23/8)
+ *    Rational(20, 9) - 9.8              #=&gt; -7.577777777777778
+ */
</ins><span class="cx"> static VALUE
</span><del>-nurat_sub(VALUE self, VALUE other)
</del><ins>+nurat_sub(VALUE self, SEL sel, VALUE other)
</ins><span class="cx"> {
</span><span class="cx">     switch (TYPE(other)) {
</span><span class="cx">       case T_FIXNUM:
</span><span class="lines">@@ -761,8 +789,22 @@
</span><span class="cx">     return f_rational_new_no_reduce2(CLASS_OF(self), num, den);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    rat * numeric  -&gt;  numeric_result
+ *
+ * Performs multiplication.
+ *
+ * For example:
+ *
+ *    Rational(2, 3)  * Rational(2, 3)   #=&gt; (4/9)
+ *    Rational(900)   * Rational(1)      #=&gt; (900/1)
+ *    Rational(-2, 9) * Rational(-9, 2)  #=&gt; (1/1)
+ *    Rational(9, 8)  * 4                #=&gt; (9/2)
+ *    Rational(20, 9) * 9.8              #=&gt; 21.77777777777778
+ */
</ins><span class="cx"> static VALUE
</span><del>-nurat_mul(VALUE self, VALUE other)
</del><ins>+nurat_mul(VALUE self, SEL sel, VALUE other)
</ins><span class="cx"> {
</span><span class="cx">     switch (TYPE(other)) {
</span><span class="cx">       case T_FIXNUM:
</span><span class="lines">@@ -789,14 +831,29 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    rat / numeric     -&gt;  numeric_result
+ *    rat.quo(numeric)  -&gt;  numeric_result
+ *
+ * Performs division.
+ *
+ * For example:
+ *
+ *    Rational(2, 3)  / Rational(2, 3)   #=&gt; (1/1)
+ *    Rational(900)   / Rational(1)      #=&gt; (900/1)
+ *    Rational(-2, 9) / Rational(-9, 2)  #=&gt; (4/81)
+ *    Rational(9, 8)  / 4                #=&gt; (9/32)
+ *    Rational(20, 9) / 9.8              #=&gt; 0.22675736961451246
+ */
</ins><span class="cx"> static VALUE
</span><del>-nurat_div(VALUE self, VALUE other)
</del><ins>+nurat_div(VALUE self, SEL sel, VALUE other)
</ins><span class="cx"> {
</span><span class="cx">     switch (TYPE(other)) {
</span><span class="cx">       case T_FIXNUM:
</span><span class="cx">       case T_BIGNUM:
</span><span class="cx">         if (f_zero_p(other))
</span><del>-            rb_raise(rb_eZeroDivError, &quot;devided by zero&quot;);
</del><ins>+            rb_raise_zerodiv();
</ins><span class="cx">         {
</span><span class="cx">             get_dat1(self);
</span><span class="cx"> 
</span><span class="lines">@@ -808,10 +865,14 @@
</span><span class="cx">         return rb_funcall(f_to_f(self), '/', 1, other);
</span><span class="cx">       case T_RATIONAL:
</span><span class="cx">         if (f_zero_p(other))
</span><del>-            rb_raise(rb_eZeroDivError, &quot;devided by zero&quot;);
</del><ins>+            rb_raise_zerodiv();
</ins><span class="cx">         {
</span><span class="cx">             get_dat2(self, other);
</span><span class="cx"> 
</span><ins>+            if (f_one_p(self))
+                return f_rational_new_no_reduce2(CLASS_OF(self),
+                                                 bdat-&gt;den, bdat-&gt;num);
+
</ins><span class="cx">             return f_muldiv(self,
</span><span class="cx">                             adat-&gt;num, adat-&gt;den,
</span><span class="cx">                             bdat-&gt;num, bdat-&gt;den, '/');
</span><span class="lines">@@ -821,28 +882,58 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    rat.fdiv(numeric)  -&gt;  float
+ *
+ * Performs division and returns the value as a float.
+ *
+ * For example:
+ *
+ *    Rational(2, 3).fdiv(1)       #=&gt; 0.6666666666666666
+ *    Rational(2, 3).fdiv(0.5)     #=&gt; 1.3333333333333333
+ *    Rational(2).fdiv(3)          #=&gt; 0.6666666666666666
+ */
</ins><span class="cx"> static VALUE
</span><del>-nurat_fdiv(VALUE self, VALUE other)
</del><ins>+nurat_fdiv(VALUE self, SEL sel, VALUE other)
</ins><span class="cx"> {
</span><del>-    return f_div(f_to_f(self), other);
</del><ins>+    if (f_zero_p(other))
+        return f_div(self, f_to_f(other));
+    return f_to_f(f_div(self, other));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+extern VALUE rb_fexpt(VALUE x, VALUE y);
+
+/*
+ * call-seq:
+ *    rat ** numeric  -&gt;  numeric_result
+ *
+ * Performs exponentiation.
+ *
+ * For example:
+ *
+ *    Rational(2)    ** Rational(3)    #=&gt; (8/1)
+ *    Rational(10)   ** -2             #=&gt; (1/100)
+ *    Rational(10)   ** -2.0           #=&gt; 0.01
+ *    Rational(-4)   ** Rational(1,2)  #=&gt; (1.2246063538223773e-16+2.0i)
+ *    Rational(1, 2) ** 0              #=&gt; (1/1)
+ *    Rational(1, 2) ** 0.0            #=&gt; 1.0
+ */
</ins><span class="cx"> static VALUE
</span><del>-nurat_expt(VALUE self, VALUE other)
</del><ins>+nurat_expt(VALUE self, SEL sel, VALUE other)
</ins><span class="cx"> {
</span><del>-    if (f_zero_p(other))
</del><ins>+    if (k_exact_zero_p(other))
</ins><span class="cx">         return f_rational_new_bang1(CLASS_OF(self), ONE);
</span><span class="cx"> 
</span><span class="cx">     if (k_rational_p(other)) {
</span><span class="cx">         get_dat1(other);
</span><span class="cx"> 
</span><span class="cx">         if (f_one_p(dat-&gt;den))
</span><del>-            other = dat-&gt;num; /* good? */
</del><ins>+            other = dat-&gt;num; /* c14n */
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     switch (TYPE(other)) {
</span><span class="cx">       case T_FIXNUM:
</span><del>-      case T_BIGNUM:
</del><span class="cx">         {
</span><span class="cx">             VALUE num, den;
</span><span class="cx"> 
</span><span class="lines">@@ -864,6 +955,9 @@
</span><span class="cx">             }
</span><span class="cx">             return f_rational_new2(CLASS_OF(self), num, den);
</span><span class="cx">         }
</span><ins>+      case T_BIGNUM:
+        rb_warn(&quot;in a**b, b may be too big&quot;);
+        /* fall through */
</ins><span class="cx">       case T_FLOAT:
</span><span class="cx">       case T_RATIONAL:
</span><span class="cx">         return f_expt(f_to_f(self), other);
</span><span class="lines">@@ -872,8 +966,22 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    rat &lt;=&gt; numeric  -&gt;  -1, 0, +1 or nil
+ *
+ * Performs comparison and returns -1, 0, or +1.
+ *
+ * For example:
+ *
+ *    Rational(2, 3)  &lt;=&gt; Rational(2, 3)  #=&gt; 0
+ *    Rational(5)     &lt;=&gt; 5               #=&gt; 0
+ *    Rational(2,3)   &lt;=&gt; Rational(1,3)   #=&gt; 1
+ *    Rational(1,3)   &lt;=&gt; 1               #=&gt; -1
+ *    Rational(1,3)   &lt;=&gt; 0.3             #=&gt; 1
+ */
</ins><span class="cx"> static VALUE
</span><del>-nurat_cmp(VALUE self, VALUE other)
</del><ins>+nurat_cmp(VALUE self, SEL sel, VALUE other)
</ins><span class="cx"> {
</span><span class="cx">     switch (TYPE(other)) {
</span><span class="cx">       case T_FIXNUM:
</span><span class="lines">@@ -882,9 +990,8 @@
</span><span class="cx">             get_dat1(self);
</span><span class="cx"> 
</span><span class="cx">             if (FIXNUM_P(dat-&gt;den) &amp;&amp; FIX2LONG(dat-&gt;den) == 1)
</span><del>-                return f_cmp(dat-&gt;num, other);
-            else
-                return f_cmp(self, f_rational_new_bang1(CLASS_OF(self), other));
</del><ins>+                return f_cmp(dat-&gt;num, other); /* c14n */
+            return f_cmp(self, f_rational_new_bang1(CLASS_OF(self), other));
</ins><span class="cx">         }
</span><span class="cx">       case T_FLOAT:
</span><span class="cx">         return f_cmp(f_to_f(self), other);
</span><span class="lines">@@ -906,12 +1013,26 @@
</span><span class="cx">             return f_cmp(f_sub(num1, num2), ZERO);
</span><span class="cx">         }
</span><span class="cx">       default:
</span><del>-        return rb_num_coerce_bin(self, other, id_cmp);
</del><ins>+        return rb_num_coerce_cmp(self, other, id_cmp);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    rat == object  -&gt;  true or false
+ *
+ * Returns true if rat equals object numerically.
+ *
+ * For example:
+ *
+ *    Rational(2, 3)  == Rational(2, 3)   #=&gt; true
+ *    Rational(5)     == 5                #=&gt; true
+ *    Rational(0)     == 0.0              #=&gt; true
+ *    Rational('1/3') == 0.33             #=&gt; false
+ *    Rational('1/2') == '1/2'            #=&gt; false
+ */
</ins><span class="cx"> static VALUE
</span><del>-nurat_equal_p(VALUE self, VALUE other)
</del><ins>+nurat_eqeq_p(VALUE self, SEL sel, VALUE other)
</ins><span class="cx"> {
</span><span class="cx">     switch (TYPE(other)) {
</span><span class="cx">       case T_FIXNUM:
</span><span class="lines">@@ -919,31 +1040,37 @@
</span><span class="cx">         {
</span><span class="cx">             get_dat1(self);
</span><span class="cx"> 
</span><ins>+            if (f_zero_p(dat-&gt;num) &amp;&amp; f_zero_p(other))
+                return Qtrue;
+
</ins><span class="cx">             if (!FIXNUM_P(dat-&gt;den))
</span><span class="cx">                 return Qfalse;
</span><span class="cx">             if (FIX2LONG(dat-&gt;den) != 1)
</span><span class="cx">                 return Qfalse;
</span><del>-            if (f_equal_p(dat-&gt;num, other))
</del><ins>+            if (f_eqeq_p(dat-&gt;num, other))
</ins><span class="cx">                 return Qtrue;
</span><del>-            else
-                return Qfalse;
</del><ins>+            return Qfalse;
</ins><span class="cx">         }
</span><span class="cx">       case T_FLOAT:
</span><del>-        return f_equal_p(f_to_f(self), other);
</del><ins>+        return f_eqeq_p(f_to_f(self), other);
</ins><span class="cx">       case T_RATIONAL:
</span><span class="cx">         {
</span><span class="cx">             get_dat2(self, other);
</span><span class="cx"> 
</span><del>-            return f_boolcast(f_equal_p(adat-&gt;num, bdat-&gt;num) &amp;&amp;
-                              f_equal_p(adat-&gt;den, bdat-&gt;den));
</del><ins>+            if (f_zero_p(adat-&gt;num) &amp;&amp; f_zero_p(bdat-&gt;num))
+                return Qtrue;
+
+            return f_boolcast(f_eqeq_p(adat-&gt;num, bdat-&gt;num) &amp;&amp;
+                              f_eqeq_p(adat-&gt;den, bdat-&gt;den));
</ins><span class="cx">         }
</span><span class="cx">       default:
</span><del>-        return f_equal_p(other, self);
</del><ins>+        return f_eqeq_p(other, self);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/* :nodoc: */
</ins><span class="cx"> static VALUE
</span><del>-nurat_coerce(VALUE self, VALUE other)
</del><ins>+nurat_coerce(VALUE self, SEL sel, VALUE other)
</ins><span class="cx"> {
</span><span class="cx">     switch (TYPE(other)) {
</span><span class="cx">       case T_FIXNUM:
</span><span class="lines">@@ -951,6 +1078,12 @@
</span><span class="cx">         return rb_assoc_new(f_rational_new_bang1(CLASS_OF(self), other), self);
</span><span class="cx">       case T_FLOAT:
</span><span class="cx">         return rb_assoc_new(other, f_to_f(self));
</span><ins>+      case T_RATIONAL:
+        return rb_assoc_new(other, self);
+      case T_COMPLEX:
+        if (k_exact_zero_p(RCOMPLEX(other)-&gt;imag))
+            return rb_assoc_new(f_rational_new_bang1
+                                (CLASS_OF(self), RCOMPLEX(other)-&gt;real), self);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     rb_raise(rb_eTypeError, &quot;%s can't be coerced into %s&quot;,
</span><span class="lines">@@ -958,43 +1091,23 @@
</span><span class="cx">     return Qnil;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#if 0
+/* :nodoc: */
</ins><span class="cx"> static VALUE
</span><span class="cx"> nurat_idiv(VALUE self, VALUE other)
</span><span class="cx"> {
</span><del>-    return f_floor(f_div(self, other));
</del><ins>+    return f_idiv(self, other);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/* :nodoc: */
</ins><span class="cx"> static VALUE
</span><del>-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
</del><span class="cx"> nurat_quot(VALUE self, VALUE other)
</span><span class="cx"> {
</span><span class="cx">     return f_truncate(f_div(self, other));
</span><span class="cx"> }
</span><del>-#endif
</del><span class="cx"> 
</span><ins>+/* :nodoc: */
</ins><span class="cx"> static VALUE
</span><del>-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
</del><span class="cx"> nurat_quotrem(VALUE self, VALUE other)
</span><span class="cx"> {
</span><span class="cx">     VALUE val = f_truncate(f_div(self, other));
</span><span class="lines">@@ -1002,16 +1115,8 @@
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-static VALUE
-nurat_abs(VALUE self)
-{
-    if (!f_negative_p(self))
-        return self;
-    else
-        return f_negate(self);
-}
-
</del><span class="cx"> #if 0
</span><ins>+/* :nodoc: */
</ins><span class="cx"> static VALUE
</span><span class="cx"> nurat_true(VALUE self)
</span><span class="cx"> {
</span><span class="lines">@@ -1020,21 +1125,39 @@
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> static VALUE
</span><del>-nurat_floor(VALUE self)
</del><ins>+nurat_floor(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><span class="cx">     get_dat1(self);
</span><span class="cx">     return f_idiv(dat-&gt;num, dat-&gt;den);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static VALUE
</span><del>-nurat_ceil(VALUE self)
</del><ins>+nurat_ceil(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><span class="cx">     get_dat1(self);
</span><span class="cx">     return f_negate(f_idiv(f_negate(dat-&gt;num), dat-&gt;den));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+
+/*
+ * call-seq:
+ *    rat.to_i  -&gt;  integer
+ *
+ * Returns the truncated value as an integer.
+ *
+ * Equivalent to
+ *    rat.truncate.
+ *
+ * For example:
+ *
+ *    Rational(2, 3).to_i   #=&gt; 0
+ *    Rational(3).to_i      #=&gt; 3
+ *    Rational(300.6).to_i  #=&gt; 300
+ *    Rational(98,71).to_i  #=&gt; 1
+ *    Rational(-30,2).to_i  #=&gt; -15
+ */
</ins><span class="cx"> static VALUE
</span><del>-nurat_truncate(VALUE self)
</del><ins>+nurat_truncate(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><span class="cx">     get_dat1(self);
</span><span class="cx">     if (f_negative_p(dat-&gt;num))
</span><span class="lines">@@ -1043,158 +1166,291 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static VALUE
</span><del>-nurat_round(VALUE self)
</del><ins>+nurat_round(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><ins>+    VALUE num, den, neg;
+
</ins><span class="cx">     get_dat1(self);
</span><span class="cx"> 
</span><del>-    if (f_negative_p(dat-&gt;num)) {
-        VALUE num, den;
</del><ins>+    num = dat-&gt;num;
+    den = dat-&gt;den;
+    neg = f_negative_p(num);
</ins><span class="cx"> 
</span><del>-        num = f_negate(dat-&gt;num);
-        num = f_add(f_mul(num, TWO), dat-&gt;den);
-        den = f_mul(dat-&gt;den, TWO);
-        return f_negate(f_idiv(num, den));
-    }
-    else {
-        VALUE num = f_add(f_mul(dat-&gt;num, TWO), dat-&gt;den);
-        VALUE den = f_mul(dat-&gt;den, TWO);
-        return f_idiv(num, den);
-    }
-}
</del><ins>+    if (neg)
+        num = f_negate(num);
</ins><span class="cx"> 
</span><del>-#define f_size(x) rb_funcall(x, rb_intern(&quot;size&quot;), 0)
-#define f_rshift(x,y) rb_funcall(x, rb_intern(&quot;&gt;&gt;&quot;), 1, y)
</del><ins>+    num = f_add(f_mul(num, TWO), den);
+    den = f_mul(den, TWO);
+    num = f_idiv(num, den);
</ins><span class="cx"> 
</span><del>-inline static long
-i_ilog2(VALUE x)
-{
-    long q, r, fx;
</del><ins>+    if (neg)
+        num = f_negate(num);
</ins><span class="cx"> 
</span><del>-    assert(!f_lt_p(x, ONE));
-
-    q = (NUM2LONG(f_size(x)) - sizeof(long)) * 8 + 1;
-
-    if (q &gt; 0)
-        x = f_rshift(x, LONG2NUM(q));
-
-    fx = NUM2LONG(x);
-
-    r = -1;
-    while (fx) {
-        fx &gt;&gt;= 1;
-        r += 1;
-    }
-
-    return q + r;
</del><ins>+    return num;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static VALUE
</span><del>-nurat_to_f(VALUE self)
</del><ins>+f_round_common(int argc, VALUE *argv, VALUE self, VALUE (*func)(VALUE, SEL))
</ins><span class="cx"> {
</span><del>-    VALUE num, den;
-    int minus = 0;
-    long nl, dl, ml, ne, de;
-    int e;
-    double f;
</del><ins>+    VALUE n, b, s;
</ins><span class="cx"> 
</span><del>-    {
-        get_dat1(self);
</del><ins>+    if (argc == 0)
+        return (*func)(self, NULL);
</ins><span class="cx"> 
</span><del>-        if (f_zero_p(dat-&gt;num))
-            return rb_float_new(0.0);
</del><ins>+    rb_scan_args(argc, argv, &quot;01&quot;, &amp;n);
</ins><span class="cx"> 
</span><del>-        num = dat-&gt;num;
-        den = dat-&gt;den;
-    }
</del><ins>+    if (!k_integer_p(n))
+        rb_raise(rb_eTypeError, &quot;not an integer&quot;);
</ins><span class="cx"> 
</span><del>-    if (f_negative_p(num)) {
-        num = f_negate(num);
-        minus = 1;
-    }
</del><ins>+    b = f_expt(INT2FIX(10), n);
+    s = f_mul(self, b);
</ins><span class="cx"> 
</span><del>-    nl = i_ilog2(num);
-    dl = i_ilog2(den);
-    ml = (long)(log(DBL_MAX) / log(2.0) - 1); /* should be a static */
</del><ins>+    s = (*func)(s, NULL);
</ins><span class="cx"> 
</span><del>-    ne = 0;
-    if (nl &gt; ml) {
-        ne = nl - ml;
-        num = f_rshift(num, LONG2NUM(ne));
-    }
</del><ins>+    s = f_div(f_rational_new_bang1(CLASS_OF(self), s), b);
</ins><span class="cx"> 
</span><del>-    de = 0;
-    if (dl &gt; ml) {
-        de = dl - ml;
-        den = f_rshift(den, LONG2NUM(de));
-    }
</del><ins>+    if (f_lt_p(n, ONE))
+        s = f_to_i(s);
</ins><span class="cx"> 
</span><del>-    e = (int)(ne - de);
</del><ins>+    return s;
+}
</ins><span class="cx"> 
</span><del>-    if ((e &gt; DBL_MAX_EXP) || (e &lt; DBL_MIN_EXP)) {
-        rb_warning(&quot;%s out of Float range&quot;, rb_obj_classname(self));
-        return rb_float_new(e &gt; 0 ? HUGE_VAL : 0.0);
-    }
</del><ins>+/*
+ * call-seq:
+ *    rat.floor               -&gt;  integer
+ *    rat.floor(precision=0)  -&gt;  rational
+ *
+ * Returns the truncated value (toward negative infinity).
+ *
+ * For example:
+ *
+ *    Rational(3).floor      #=&gt; 3
+ *    Rational(2, 3).floor   #=&gt; 0
+ *    Rational(-3, 2).floor  #=&gt; -1
+ *
+ *           decimal      -  1  2  3 . 4  5  6
+ *                          ^  ^  ^  ^   ^  ^
+ *          precision      -3 -2 -1  0  +1 +2
+ *
+ *    '%f' % Rational('-123.456').floor(+1)  #=&gt; &quot;-123.500000&quot;
+ *    '%f' % Rational('-123.456').floor(-1)  #=&gt; &quot;-130.000000&quot;
+ */
+static VALUE
+nurat_floor_n(VALUE self, SEL sel, int argc, VALUE *argv)
+{
+    return f_round_common(argc, argv, self, nurat_floor);
+}
</ins><span class="cx"> 
</span><del>-    f = NUM2DBL(num) / NUM2DBL(den);
-    if (minus)
-        f = -f;
-    f = ldexp(f, e);
</del><ins>+/*
+ * call-seq:
+ *    rat.ceil               -&gt;  integer
+ *    rat.ceil(precision=0)  -&gt;  rational
+ *
+ * Returns the truncated value (toward positive infinity).
+ *
+ * For example:
+ *
+ *    Rational(3).ceil      #=&gt; 3
+ *    Rational(2, 3).ceil   #=&gt; 1
+ *    Rational(-3, 2).ceil  #=&gt; -1
+ *
+ *           decimal      -  1  2  3 . 4  5  6
+ *                          ^  ^  ^  ^   ^  ^
+ *          precision      -3 -2 -1  0  +1 +2
+ *
+ *    '%f' % Rational('-123.456').ceil(+1)  #=&gt; &quot;-123.400000&quot;
+ *    '%f' % Rational('-123.456').ceil(-1)  #=&gt; &quot;-120.000000&quot;
+ */
+static VALUE
+nurat_ceil_n(VALUE self, SEL sel, int argc, VALUE *argv)
+{
+    return f_round_common(argc, argv, self, nurat_ceil);
+}
</ins><span class="cx"> 
</span><del>-    if (isinf(f) || isnan(f))
-        rb_warning(&quot;%s out of Float range&quot;, rb_obj_classname(self));
</del><ins>+/*
+ * call-seq:
+ *    rat.truncate               -&gt;  integer
+ *    rat.truncate(precision=0)  -&gt;  rational
+ *
+ * Returns the truncated value (toward zero).
+ *
+ * For example:
+ *
+ *    Rational(3).truncate      #=&gt; 3
+ *    Rational(2, 3).truncate   #=&gt; 0
+ *    Rational(-3, 2).truncate  #=&gt; -1
+ *
+ *           decimal      -  1  2  3 . 4  5  6
+ *                          ^  ^  ^  ^   ^  ^
+ *          precision      -3 -2 -1  0  +1 +2
+ *
+ *    '%f' % Rational('-123.456').truncate(+1)  #=&gt;  &quot;-123.400000&quot;
+ *    '%f' % Rational('-123.456').truncate(-1)  #=&gt;  &quot;-120.000000&quot;
+ */
+static VALUE
+nurat_truncate_n(VALUE self, SEL sel, int argc, VALUE *argv)
+{
+    return f_round_common(argc, argv, self, nurat_truncate);
+}
</ins><span class="cx"> 
</span><del>-    return rb_float_new(f);
</del><ins>+/*
+ * call-seq:
+ *    rat.round               -&gt;  integer
+ *    rat.round(precision=0)  -&gt;  rational
+ *
+ * Returns the truncated value (toward the nearest integer;
+ * 0.5 =&gt; 1; -0.5 =&gt; -1).
+ *
+ * For example:
+ *
+ *    Rational(3).round      #=&gt; 3
+ *    Rational(2, 3).round   #=&gt; 1
+ *    Rational(-3, 2).round  #=&gt; -2
+ *
+ *           decimal      -  1  2  3 . 4  5  6
+ *                          ^  ^  ^  ^   ^  ^
+ *          precision      -3 -2 -1  0  +1 +2
+ *
+ *    '%f' % Rational('-123.456').round(+1)  #=&gt; &quot;-123.500000&quot;
+ *    '%f' % Rational('-123.456').round(-1)  #=&gt; &quot;-120.000000&quot;
+ */
+static VALUE
+nurat_round_n(VALUE self, SEL sel, int argc, VALUE *argv)
+{
+    return f_round_common(argc, argv, self, nurat_round);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    rat.to_f  -&gt;  float
+ *
+ * Return the value as a float.
+ *
+ * For example:
+ *
+ *    Rational(2).to_f      #=&gt; 2.0
+ *    Rational(9, 4).to_f   #=&gt; 2.25
+ *    Rational(-3, 4).to_f  #=&gt; -0.75
+ *    Rational(20, 3).to_f  #=&gt; 6.666666666666667
+ */
</ins><span class="cx"> static VALUE
</span><del>-nurat_to_r(VALUE self)
</del><ins>+nurat_to_f(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><ins>+    get_dat1(self);
+    return f_fdiv(dat-&gt;num, dat-&gt;den);
+}
+
+/*
+ * call-seq:
+ *    rat.to_r  -&gt;  self
+ *
+ * Returns self.
+ *
+ * For example:
+ *
+ *    Rational(2).to_r      #=&gt; (2/1)
+ *    Rational(-8, 6).to_r  #=&gt; (-4/3)
+ */
+static VALUE
+nurat_to_r(VALUE self, SEL sel)
+{
</ins><span class="cx">     return self;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/* :nodoc: */
</ins><span class="cx"> static VALUE
</span><del>-nurat_hash(VALUE self)
</del><ins>+nurat_hash(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><ins>+    long v, h[2];
+    VALUE n;
+
</ins><span class="cx">     get_dat1(self);
</span><del>-    return f_xor(dat-&gt;num, dat-&gt;den);
</del><ins>+    n = rb_hash(dat-&gt;num);
+    h[0] = NUM2LONG(n);
+    n = rb_hash(dat-&gt;den);
+    h[1] = NUM2LONG(n);
+    v = rb_memhash(h, sizeof(h));
+    return LONG2FIX(v);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static VALUE
</span><del>-nurat_to_s(VALUE self)
</del><ins>+f_format(VALUE self, VALUE (*func)(VALUE))
</ins><span class="cx"> {
</span><ins>+    VALUE s;
</ins><span class="cx">     get_dat1(self);
</span><span class="cx"> 
</span><del>-    if (f_one_p(dat-&gt;den))
-        return f_to_s(dat-&gt;num);
-    else
-        return rb_funcall(rb_mKernel, id_format, 3,
-                          rb_str_new2(&quot;%d/%d&quot;), dat-&gt;num, dat-&gt;den);
</del><ins>+    s = (*func)(dat-&gt;num);
+    rb_str_cat2(s, &quot;/&quot;);
+    rb_str_concat(s, (*func)(dat-&gt;den));
+
+    return s;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    rat.to_s  -&gt;  string
+ *
+ * Returns the value as a string.
+ *
+ * For example:
+ *
+ *    Rational(2).to_s      #=&gt; &quot;2/1&quot;
+ *    Rational(-8, 6).to_s  #=&gt; &quot;-4/3&quot;
+ *    Rational('0.5').to_s  #=&gt; &quot;1/2&quot;
+ */
</ins><span class="cx"> static VALUE
</span><del>-nurat_inspect(VALUE self)
</del><ins>+nurat_to_s(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><del>-    get_dat1(self);
-    return rb_funcall(rb_mKernel, id_format, 3,
-                      rb_str_new2(&quot;Rational(%d, %d)&quot;), dat-&gt;num, dat-&gt;den);
</del><ins>+    return f_format(self, f_to_s);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    rat.inspect  -&gt;  string
+ *
+ * Returns the value as a string for inspection.
+ *
+ * For example:
+ *
+ *    Rational(2).inspect      #=&gt; &quot;(2/1)&quot;
+ *    Rational(-8, 6).inspect  #=&gt; &quot;(-4/3)&quot;
+ *    Rational('0.5').inspect  #=&gt; &quot;(1/2)&quot;
+ */
</ins><span class="cx"> static VALUE
</span><del>-nurat_marshal_dump(VALUE self)
</del><ins>+nurat_inspect(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><ins>+    VALUE s;
+
+    s = rb_usascii_str_new2(&quot;(&quot;);
+    rb_str_concat(s, f_format(self, f_inspect));
+    rb_str_cat2(s, &quot;)&quot;);
+
+    return s;
+}
+
+/* :nodoc: */
+static VALUE
+nurat_marshal_dump(VALUE self, SEL sel)
+{
+    VALUE a;
</ins><span class="cx">     get_dat1(self);
</span><del>-    return rb_assoc_new(dat-&gt;num, dat-&gt;den);
</del><ins>+
+    a = rb_assoc_new(dat-&gt;num, dat-&gt;den);
+    rb_copy_generic_ivar(a, self);
+    return a;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/* :nodoc: */
</ins><span class="cx"> static VALUE
</span><del>-nurat_marshal_load(VALUE self, VALUE a)
</del><ins>+nurat_marshal_load(VALUE self, SEL sel, VALUE a)
</ins><span class="cx"> {
</span><span class="cx">     get_dat1(self);
</span><del>-    dat-&gt;num = RARRAY_AT(a, 0);
-    dat-&gt;den = RARRAY_AT(a, 1);
</del><ins>+    dat-&gt;num = RARRAY_PTR(a)[0];
+    dat-&gt;den = RARRAY_PTR(a)[1];
+    rb_copy_generic_ivar(self, a);
</ins><span class="cx"> 
</span><span class="cx">     if (f_zero_p(dat-&gt;den))
</span><del>-        rb_raise(rb_eZeroDivError, &quot;devided by zero&quot;);
</del><ins>+        rb_raise_zerodiv();
</ins><span class="cx"> 
</span><span class="cx">     return self;
</span><span class="cx"> }
</span><span class="lines">@@ -1202,23 +1458,68 @@
</span><span class="cx"> /* --- */
</span><span class="cx"> 
</span><span class="cx"> VALUE
</span><del>-rb_gcd(VALUE self, VALUE other)
</del><ins>+rb_rational_reciprocal(VALUE x, SEL sel)
</ins><span class="cx"> {
</span><del>-    nurat_int_check(other);
</del><ins>+    get_dat1(x);
+    return f_rational_new_no_reduce2(CLASS_OF(x), dat-&gt;den, dat-&gt;num);
+}
+
+/*
+ * call-seq:
+ *    int.gcd(int2)  -&gt;  integer
+ *
+ * Returns the greatest common divisor (always positive).  0.gcd(x)
+ * and x.gcd(0) return abs(x).
+ *
+ * For example:
+ *
+ *    2.gcd(2)                    #=&gt; 2
+ *    3.gcd(-7)                   #=&gt; 1
+ *    ((1&lt;&lt;31)-1).gcd((1&lt;&lt;61)-1)  #=&gt; 1
+ */
+VALUE
+rb_gcd(VALUE self, SEL sel, VALUE other)
+{
+    other = nurat_int_value(other);
</ins><span class="cx">     return f_gcd(self, other);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    int.lcm(int2)  -&gt;  integer
+ *
+ * Returns the least common multiple (always positive).  0.lcm(x) and
+ * x.lcm(0) return zero.
+ *
+ * For example:
+ *
+ *    2.lcm(2)                    #=&gt; 2
+ *    3.lcm(-7)                   #=&gt; 21
+ *    ((1&lt;&lt;31)-1).lcm((1&lt;&lt;61)-1)  #=&gt; 4951760154835678088235319297
+ */
</ins><span class="cx"> VALUE
</span><del>-rb_lcm(VALUE self, VALUE other)
</del><ins>+rb_lcm(VALUE self, SEL sel, VALUE other)
</ins><span class="cx"> {
</span><del>-    nurat_int_check(other);
</del><ins>+    other = nurat_int_value(other);
</ins><span class="cx">     return f_lcm(self, other);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    int.gcdlcm(int2)  -&gt;  array
+ *
+ * Returns an array; [int.gcd(int2), int.lcm(int2)].
+ *
+ * For example:
+ *
+ *    2.gcdlcm(2)                    #=&gt; [2, 2]
+ *    3.gcdlcm(-7)                   #=&gt; [1, 21]
+ *    ((1&lt;&lt;31)-1).gcdlcm((1&lt;&lt;61)-1)  #=&gt; [1, 4951760154835678088235319297]
+ */
</ins><span class="cx"> VALUE
</span><del>-rb_gcdlcm(VALUE self, VALUE other)
</del><ins>+rb_gcdlcm(VALUE self, SEL sel, VALUE other)
</ins><span class="cx"> {
</span><del>-    nurat_int_check(other);
</del><ins>+    other = nurat_int_value(other);
</ins><span class="cx">     return rb_assoc_new(f_gcd(self, other), f_lcm(self, other));
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1234,7 +1535,7 @@
</span><span class="cx">     return nurat_s_canonicalize_internal(rb_cRational, x, y);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static VALUE nurat_s_convert(int argc, VALUE *argv, VALUE klass);
</del><ins>+static VALUE nurat_s_convert(VALUE klass, SEL sel, int argc, VALUE *argv);
</ins><span class="cx"> 
</span><span class="cx"> VALUE
</span><span class="cx"> rb_Rational(VALUE x, VALUE y)
</span><span class="lines">@@ -1242,23 +1543,138 @@
</span><span class="cx">     VALUE a[2];
</span><span class="cx">     a[0] = x;
</span><span class="cx">     a[1] = y;
</span><del>-    return nurat_s_convert(2, a, rb_cRational);
</del><ins>+    return nurat_s_convert(rb_cRational, NULL, 2, a);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#define id_numerator rb_intern(&quot;numerator&quot;)
+#define f_numerator(x) rb_funcall(x, id_numerator, 0)
+
+#define id_denominator rb_intern(&quot;denominator&quot;)
+#define f_denominator(x) rb_funcall(x, id_denominator, 0)
+
+#define id_to_r rb_intern(&quot;to_r&quot;)
+#define f_to_r(x) rb_funcall(x, id_to_r, 0)
+
+/*
+ * call-seq:
+ *    num.numerator  -&gt;  integer
+ *
+ * Returns the numerator.
+ */
</ins><span class="cx"> static VALUE
</span><del>-nilclass_to_r(VALUE self)
</del><ins>+numeric_numerator(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><ins>+    return f_numerator(f_to_r(self));
+}
+
+/*
+ * call-seq:
+ *    num.denominator  -&gt;  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  -&gt;  self
+ *
+ * Returns self.
+ */
+static VALUE
+integer_numerator(VALUE self, SEL sel)
+{
+    return self;
+}
+
+/*
+ * call-seq:
+ *    int.denominator  -&gt;  1
+ *
+ * Returns 1.
+ */
+static VALUE
+integer_denominator(VALUE self, SEL sel)
+{
+    return INT2FIX(1);
+}
+
+/*
+ * call-seq:
+ *    flo.numerator  -&gt;  integer
+ *
+ * Returns the numerator.  The result is machine dependent.
+ *
+ * For example:
+ *
+ *    n = 0.3.numerator    #=&gt; 5404319552844595
+ *    d = 0.3.denominator  #=&gt; 18014398509481984
+ *    n.fdiv(d)            #=&gt; 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  -&gt;  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  -&gt;  (0/1)
+ *
+ * Returns zero as a rational.
+ */
+static VALUE
+nilclass_to_r(VALUE self, SEL sel)
+{
</ins><span class="cx">     return rb_rational_new1(INT2FIX(0));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    int.to_r  -&gt;  rational
+ *
+ * Returns the value as a rational.
+ *
+ * For example:
+ *
+ *    1.to_r        #=&gt; (1/1)
+ *    (1&lt;&lt;64).to_r  #=&gt; (18446744073709551616/1)
+ */
</ins><span class="cx"> static VALUE
</span><del>-integer_to_r(VALUE self)
</del><ins>+integer_to_r(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><span class="cx">     return rb_rational_new1(self);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static VALUE
-float_decode(VALUE self)
</del><ins>+static void
+float_decode_internal(VALUE self, VALUE *rf, VALUE *rn)
</ins><span class="cx"> {
</span><span class="cx">     double f;
</span><span class="cx">     int n;
</span><span class="lines">@@ -1266,52 +1682,102 @@
</span><span class="cx">     f = frexp(RFLOAT_VALUE(self), &amp;n);
</span><span class="cx">     f = ldexp(f, DBL_MANT_DIG);
</span><span class="cx">     n -= DBL_MANT_DIG;
</span><del>-    return rb_assoc_new(f_to_i(rb_float_new(f)), INT2FIX(n));
</del><ins>+    *rf = rb_dbl2big(f);
+    *rn = INT2FIX(n);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#if 0
</ins><span class="cx"> static VALUE
</span><del>-float_to_r(VALUE self)
</del><ins>+float_decode(VALUE self)
</ins><span class="cx"> {
</span><del>-    VALUE a = float_decode(self);
-    return f_mul(RARRAY_AT(a, 0),
-                 f_expt(INT2FIX(FLT_RADIX), RARRAY_AT(a, 1)));
</del><ins>+    VALUE f, n;
+
+    float_decode_internal(self, &amp;f, &amp;n);
+    return rb_assoc_new(f, n);
</ins><span class="cx"> }
</span><ins>+#endif
</ins><span class="cx"> 
</span><ins>+#define id_lshift rb_intern(&quot;&lt;&lt;&quot;)
+#define f_lshift(x,n) rb_funcall(x, id_lshift, 1, n)
+
+/*
+ * call-seq:
+ *    flt.to_r  -&gt;  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    #=&gt; (2/1)
+ *    2.5.to_r    #=&gt; (5/2)
+ *    -0.75.to_r  #=&gt; (-3/4)
+ *    0.0.to_r    #=&gt; (0/1)
+ */
+static VALUE
+float_to_r(VALUE self, SEL sel)
+{
+    VALUE f, n;
+
+    float_decode_internal(self, &amp;f, &amp;n);
+#if FLT_RADIX == 2
+    {
+        long ln = FIX2LONG(n);
+
+        if (ln == 0)
+            return f_to_r(f);
+        if (ln &gt; 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
+}
+
</ins><span class="cx"> static VALUE rat_pat, an_e_pat, a_dot_pat, underscores_pat, an_underscore;
</span><span class="cx"> 
</span><del>-#define DIGITS &quot;(?:\\d(?:_\\d|\\d)*)&quot;
</del><ins>+#define WS &quot;\\s*&quot;
+#define DIGITS &quot;(?:[0-9](?:_[0-9]|[0-9])*)&quot;
</ins><span class="cx"> #define NUMERATOR &quot;(?:&quot; DIGITS &quot;?\\.)?&quot; DIGITS &quot;(?:[eE][-+]?&quot; DIGITS &quot;)?&quot;
</span><del>-#define DENOMINATOR &quot;[-+]?&quot; DIGITS
-#define PATTERN &quot;\\A([-+])?(&quot; NUMERATOR &quot;)(?:\\/(&quot; DENOMINATOR &quot;))?&quot;
</del><ins>+#define DENOMINATOR DIGITS
+#define PATTERN &quot;\\A&quot; WS &quot;([-+])?(&quot; NUMERATOR &quot;)(?:\\/(&quot; DENOMINATOR &quot;))?&quot; WS
</ins><span class="cx"> 
</span><span class="cx"> static void
</span><span class="cx"> make_patterns(void)
</span><span class="cx"> {
</span><del>-    static char rat_pat_source[] = PATTERN;
-    static char an_e_pat_source[] = &quot;[eE]&quot;;
-    static char a_dot_pat_source[] = &quot;\\.&quot;;
-    static char underscores_pat_source[] = &quot;_+&quot;;
</del><ins>+    static const char rat_pat_source[] = PATTERN;
+    static const char an_e_pat_source[] = &quot;[eE]&quot;;
+    static const char a_dot_pat_source[] = &quot;\\.&quot;;
+    static const char underscores_pat_source[] = &quot;_+&quot;;
</ins><span class="cx"> 
</span><ins>+    if (rat_pat) return;
+
</ins><span class="cx">     rat_pat = rb_reg_new(rat_pat_source, sizeof rat_pat_source - 1, 0);
</span><span class="cx">     rb_global_variable(&amp;rat_pat);
</span><ins>+//    rb_gc_register_mark_object(rat_pat);
</ins><span class="cx"> 
</span><span class="cx">     an_e_pat = rb_reg_new(an_e_pat_source, sizeof an_e_pat_source - 1, 0);
</span><span class="cx">     rb_global_variable(&amp;an_e_pat);
</span><ins>+//    rb_gc_register_mark_object(an_e_pat);
</ins><span class="cx"> 
</span><span class="cx">     a_dot_pat = rb_reg_new(a_dot_pat_source, sizeof a_dot_pat_source - 1, 0);
</span><span class="cx">     rb_global_variable(&amp;a_dot_pat);
</span><ins>+//    rb_gc_register_mark_object(a_dot_pat);
</ins><span class="cx"> 
</span><span class="cx">     underscores_pat = rb_reg_new(underscores_pat_source,
</span><span class="cx">                                  sizeof underscores_pat_source - 1, 0);
</span><span class="cx">     rb_global_variable(&amp;underscores_pat);
</span><ins>+//    rb_gc_register_mark_object(underscores_pat);
</ins><span class="cx"> 
</span><del>-    an_underscore = rb_str_new2(&quot;_&quot;);
</del><ins>+    an_underscore = rb_usascii_str_new2(&quot;_&quot;);
</ins><span class="cx">     rb_global_variable(&amp;an_underscore);
</span><ins>+//    rb_gc_register_mark_object(an_underscore);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-#define id_strip rb_intern(&quot;strip&quot;)
-#define f_strip(x) rb_funcall(x, id_strip, 0)
-
</del><span class="cx"> #define id_match rb_intern(&quot;match&quot;)
</span><span class="cx"> #define f_match(x,y) rb_funcall(x, id_match, 1, y)
</span><span class="cx"> 
</span><span class="lines">@@ -1324,6 +1790,9 @@
</span><span class="cx"> #define id_split rb_intern(&quot;split&quot;)
</span><span class="cx"> #define f_split(x,y) rb_funcall(x, id_split, 1, y)
</span><span class="cx"> 
</span><ins>+#define id_strip rb_intern(&quot;strip&quot;)
+#define f_strip(x) rb_funcall(x, id_strip, 0)
+
</ins><span class="cx"> #include &lt;ctype.h&gt;
</span><span class="cx"> 
</span><span class="cx"> static VALUE
</span><span class="lines">@@ -1331,7 +1800,7 @@
</span><span class="cx"> {
</span><span class="cx">     VALUE s, m;
</span><span class="cx"> 
</span><del>-    s = f_strip(self);
</del><ins>+    s = self;
</ins><span class="cx"> 
</span><span class="cx">     if (RSTRING_LEN(s) == 0)
</span><span class="cx">         return rb_assoc_new(Qnil, self);
</span><span class="lines">@@ -1349,18 +1818,18 @@
</span><span class="cx">             VALUE a;
</span><span class="cx"> 
</span><span class="cx">             a = f_split(nu, an_e_pat);
</span><del>-            ifp = RARRAY_AT(a, 0);
</del><ins>+            ifp = RARRAY_PTR(a)[0];
</ins><span class="cx">             if (RARRAY_LEN(a) != 2)
</span><span class="cx">                 exp = Qnil;
</span><span class="cx">             else
</span><del>-                exp = RARRAY_AT(a, 1);
</del><ins>+                exp = RARRAY_PTR(a)[1];
</ins><span class="cx"> 
</span><span class="cx">             a = f_split(ifp, a_dot_pat);
</span><del>-            ip = RARRAY_AT(a, 0);
</del><ins>+            ip = RARRAY_PTR(a)[0];
</ins><span class="cx">             if (RARRAY_LEN(a) != 2)
</span><span class="cx">                 fp = Qnil;
</span><span class="cx">             else
</span><del>-                fp = RARRAY_AT(a, 1);
</del><ins>+                fp = RARRAY_PTR(a)[1];
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         v = rb_rational_new1(f_to_i(ip));
</span><span class="lines">@@ -1381,10 +1850,14 @@
</span><span class="cx">             v = f_add(v, f_to_i(fp));
</span><span class="cx">             v = f_div(v, l);
</span><span class="cx">         }
</span><ins>+        if (!NIL_P(si) &amp;&amp; *StringValuePtr(si) == '-')
+            v = f_negate(v);
</ins><span class="cx">         if (!NIL_P(exp))
</span><span class="cx">             v = f_mul(v, f_expt(INT2FIX(10), f_to_i(exp)));
</span><del>-        if (!NIL_P(si) &amp;&amp; *StringValuePtr(si) == '-')
-            v = f_negate(v);
</del><ins>+#if 0
+        if (!NIL_P(de) &amp;&amp; (!NIL_P(fp) || !NIL_P(exp)))
+            return rb_assoc_new(v, rb_usascii_str_new2(&quot;dummy&quot;));
+#endif
</ins><span class="cx">         if (!NIL_P(de))
</span><span class="cx">             v = f_div(v, f_to_i(de));
</span><span class="cx"> 
</span><span class="lines">@@ -1397,24 +1870,55 @@
</span><span class="cx"> string_to_r_strict(VALUE self)
</span><span class="cx"> {
</span><span class="cx">     VALUE a = string_to_r_internal(self);
</span><del>-    if (NIL_P(RARRAY_AT(a, 0)) || RSTRING_LEN(RARRAY_AT(a, 1)) &gt; 0) {
</del><ins>+    if (NIL_P(RARRAY_PTR(a)[0]) || RSTRING_LEN(RARRAY_PTR(a)[1]) &gt; 0) {
</ins><span class="cx">         VALUE s = f_inspect(self);
</span><del>-        rb_raise(rb_eArgError, &quot;invalid value for Rational: %s&quot;,
</del><ins>+        rb_raise(rb_eArgError, &quot;invalid value for convert(): %s&quot;,
</ins><span class="cx">                  StringValuePtr(s));
</span><span class="cx">     }
</span><del>-    return RARRAY_AT(a, 0);
</del><ins>+    return RARRAY_PTR(a)[0];
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #define id_gsub rb_intern(&quot;gsub&quot;)
</span><span class="cx"> #define f_gsub(x,y,z) rb_funcall(x, id_gsub, 2, y, z)
</span><span class="cx"> 
</span><ins>+/*
+ * call-seq:
+ *    str.to_r  -&gt;  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       #=&gt; (2/1)
+ *    '300/2'.to_r       #=&gt; (150/1)
+ *    '-9.2'.to_r        #=&gt; (-46/5)
+ *    '-9.2e2'.to_r      #=&gt; (-920/1)
+ *    '1_234_567'.to_r   #=&gt; (1234567/1)
+ *    '21 june 09'.to_r  #=&gt; (21/1)
+ *    '21/06/09'.to_r    #=&gt; (7/2)
+ *    'bwv 1079'.to_r    #=&gt; (0/1)
+ */
</ins><span class="cx"> static VALUE
</span><del>-string_to_r(VALUE self)
</del><ins>+string_to_r(VALUE self, SEL sel)
</ins><span class="cx"> {
</span><del>-    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);
</del><ins>+    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];
</ins><span class="cx">     return rb_rational_new1(INT2FIX(0));
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1422,34 +1926,30 @@
</span><span class="cx"> #define f_to_r(x) rb_funcall(x, id_to_r, 0)
</span><span class="cx"> 
</span><span class="cx"> static VALUE
</span><del>-nurat_s_convert(int argc, VALUE *argv, VALUE klass)
</del><ins>+nurat_s_convert(VALUE klass, SEL sel, int argc, VALUE *argv)
</ins><span class="cx"> {
</span><del>-    VALUE a1, a2;
</del><ins>+    VALUE a1, a2, backref;
</ins><span class="cx"> 
</span><del>-    if (rb_scan_args(argc, argv, &quot;02&quot;, &amp;a1, &amp;a2) == 1) {
-        a2 = ONE;
-    }
</del><ins>+    rb_scan_args(argc, argv, &quot;11&quot;, &amp;a1, &amp;a2);
</ins><span class="cx"> 
</span><ins>+    if (NIL_P(a1) || (argc == 2 &amp;&amp; NIL_P(a2)))
+        rb_raise(rb_eTypeError, &quot;can't convert nil into Rational&quot;);
+
</ins><span class="cx">     switch (TYPE(a1)) {
</span><span class="cx">       case T_COMPLEX:
</span><del>-        if (k_float_p(RCOMPLEX(a1)-&gt;image) || !f_zero_p(RCOMPLEX(a1)-&gt;image)) {
-            VALUE s = f_to_s(a1);
-            rb_raise(rb_eRangeError, &quot;can't accept %s&quot;,
-                     StringValuePtr(s));
-        }
-        a1 = RCOMPLEX(a1)-&gt;real;
</del><ins>+        if (k_exact_zero_p(RCOMPLEX(a1)-&gt;imag))
+            a1 = RCOMPLEX(a1)-&gt;real;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     switch (TYPE(a2)) {
</span><span class="cx">       case T_COMPLEX:
</span><del>-        if (k_float_p(RCOMPLEX(a2)-&gt;image) || !f_zero_p(RCOMPLEX(a2)-&gt;image)) {
-            VALUE s = f_to_s(a2);
-            rb_raise(rb_eRangeError, &quot;can't accept %s&quot;,
-                     StringValuePtr(s));
-        }
-        a2 = RCOMPLEX(a2)-&gt;real;
</del><ins>+        if (k_exact_zero_p(RCOMPLEX(a2)-&gt;imag))
+            a2 = RCOMPLEX(a2)-&gt;real;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    backref = rb_backref_get();
+    rb_match_busy(backref);
+
</ins><span class="cx">     switch (TYPE(a1)) {
</span><span class="cx">       case T_FIXNUM:
</span><span class="cx">       case T_BIGNUM:
</span><span class="lines">@@ -1474,141 +1974,181 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    rb_backref_set(backref);
+
</ins><span class="cx">     switch (TYPE(a1)) {
</span><span class="cx">       case T_RATIONAL:
</span><del>-        if (NIL_P(a2) || f_zero_p(a2))
</del><ins>+        if (argc == 1 || (k_exact_one_p(a2)))
</ins><span class="cx">             return a1;
</span><del>-        else
</del><ins>+    }
+
+    if (argc == 1) {
+        if (!(k_numeric_p(a1) &amp;&amp; k_integer_p(a1)))
+            return rb_convert_type(a1, T_RATIONAL, &quot;Rational&quot;, &quot;to_r&quot;);
+    }
+    else {
+        if ((k_numeric_p(a1) &amp;&amp; k_numeric_p(a2)) &amp;&amp;
+            (!f_integer_p(a1) || !f_integer_p(a2)))
</ins><span class="cx">             return f_div(a1, a2);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    switch (TYPE(a2)) {
-      case T_RATIONAL:
-        return f_div(a1, a2);
</del><ins>+    {
+        VALUE argv2[2];
+        argv2[0] = a1;
+        argv2[1] = a2;
+        return nurat_s_new(argc, argv2, klass);
</ins><span class="cx">     }
</span><del>-
-    return nurat_s_new(klass, a1, a2);
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-static VALUE
-nurat_s_induced_from(VALUE klass, VALUE n)
-{
-    return f_to_r(n);
-}
-
</del><ins>+/*
+ * A rational number can be represented as a paired integer number;
+ * a/b (b&gt;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)      #=&gt; (1/1)
+ *    Rational(2, 3)   #=&gt; (2/3)
+ *    Rational(4, -6)  #=&gt; (-2/3)
+ *    3.to_r           #=&gt; (3/1)
+ *
+ * You can also create ratioanl object from floating-point numbers or
+ * strings.
+ *
+ *    Rational(0.3)    #=&gt; (5404319552844595/18014398509481984)
+ *    Rational('0.3')  #=&gt; (3/10)
+ *    Rational('2/3')  #=&gt; (2/3)
+ *
+ *    0.3.to_r         #=&gt; (5404319552844595/18014398509481984)
+ *    '0.3'.to_r       #=&gt; (3/10)
+ *    '2/3'.to_r       #=&gt; (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}              #=&gt; 0.9999999999999999
+ *    10.times.inject(0){|t,| t + Rational('0.1')}  #=&gt; (1/1)
+ *
+ * However, when an expression has inexact factor (numerical value or
+ * operation), will produce an inexact result.
+ *
+ *    Rational(10) / 3   #=&gt; (10/3)
+ *    Rational(10) / 3.0 #=&gt; 3.3333333333333335
+ *
+ *    Rational(-8) ** Rational(1, 3)
+ *                       #=&gt; (1.0000000000000002+1.7320508075688772i)
+ */
</ins><span class="cx"> void
</span><span class="cx"> Init_Rational(void)
</span><span class="cx"> {
</span><span class="cx">     assert(fprintf(stderr, &quot;assert() is now active\n&quot;));
</span><span class="cx"> 
</span><del>-    id_Unify = rb_intern(&quot;Unify&quot;);
</del><span class="cx">     id_abs = rb_intern(&quot;abs&quot;);
</span><span class="cx">     id_cmp = rb_intern(&quot;&lt;=&gt;&quot;);
</span><span class="cx">     id_convert = rb_intern(&quot;convert&quot;);
</span><del>-    id_equal_p = rb_intern(&quot;==&quot;);
</del><ins>+    id_eqeq_p = rb_intern(&quot;==&quot;);
</ins><span class="cx">     id_expt = rb_intern(&quot;**&quot;);
</span><ins>+    id_fdiv = rb_intern(&quot;fdiv&quot;);
</ins><span class="cx">     id_floor = rb_intern(&quot;floor&quot;);
</span><del>-    id_format = rb_intern(&quot;format&quot;);
</del><span class="cx">     id_idiv = rb_intern(&quot;div&quot;);
</span><span class="cx">     id_inspect = rb_intern(&quot;inspect&quot;);
</span><ins>+    id_integer_p = rb_intern(&quot;integer?&quot;);
</ins><span class="cx">     id_negate = rb_intern(&quot;-@&quot;);
</span><del>-    id_new = rb_intern(&quot;new&quot;);
-    id_new_bang = rb_intern(&quot;new!&quot;);
</del><span class="cx">     id_to_f = rb_intern(&quot;to_f&quot;);
</span><span class="cx">     id_to_i = rb_intern(&quot;to_i&quot;);
</span><span class="cx">     id_to_s = rb_intern(&quot;to_s&quot;);
</span><span class="cx">     id_truncate = rb_intern(&quot;truncate&quot;);
</span><span class="cx"> 
</span><del>-    rb_cRational = rb_define_class(RATIONAL_NAME, rb_cNumeric);
</del><ins>+    rb_cRational = rb_define_class(&quot;Rational&quot;, rb_cNumeric);
</ins><span class="cx"> 
</span><del>-    rb_define_alloc_func(rb_cRational, nurat_s_alloc);
-//    rb_funcall(rb_cRational, rb_intern(&quot;private_class_method&quot;), 1,
-//               ID2SYM(rb_intern(&quot;allocate&quot;)));
</del><ins>+    rb_objc_define_method(rb_cRational, &quot;alloc&quot;, nurat_s_alloc, 0);
+    rb_undef_method(CLASS_OF(rb_cRational), &quot;allocate&quot;);
</ins><span class="cx"> 
</span><del>-    rb_define_singleton_method(rb_cRational, &quot;new!&quot;, nurat_s_new_bang, -1);
-//    rb_funcall(rb_cRational, rb_intern(&quot;private_class_method&quot;), 1,
-//               ID2SYM(rb_intern(&quot;new!&quot;)));
</del><ins>+#if 0
+    rb_define_private_method(CLASS_OF(rb_cRational), &quot;new!&quot;, nurat_s_new_bang, -1);
+    rb_define_private_method(CLASS_OF(rb_cRational), &quot;new&quot;, nurat_s_new, -1);
+#else
+    rb_undef_method(CLASS_OF(rb_cRational), &quot;new&quot;);
+#endif
</ins><span class="cx"> 
</span><del>-    rb_define_singleton_method(rb_cRational, &quot;new&quot;, nurat_s_new_m, -1);
-//    rb_funcall(rb_cRational, rb_intern(&quot;private_class_method&quot;), 1,
-//               ID2SYM(rb_intern(&quot;new&quot;)));
</del><ins>+    rb_objc_define_method(rb_mKernel, &quot;Rational&quot;, nurat_f_rational, -1);
</ins><span class="cx"> 
</span><del>-    rb_define_global_function(RATIONAL_NAME, nurat_f_rational, -1);
</del><ins>+    rb_objc_define_method(rb_cRational, &quot;numerator&quot;, nurat_numerator, 0);
+    rb_objc_define_method(rb_cRational, &quot;denominator&quot;, nurat_denominator, 0);
</ins><span class="cx"> 
</span><del>-    rb_define_method(rb_cRational, &quot;numerator&quot;, nurat_numerator, 0);
-    rb_define_method(rb_cRational, &quot;denominator&quot;, nurat_denominator, 0);
</del><ins>+    rb_objc_define_method(rb_cRational, &quot;+&quot;, nurat_add, 1);
+    rb_objc_define_method(rb_cRational, &quot;-&quot;, nurat_sub, 1);
+    rb_objc_define_method(rb_cRational, &quot;*&quot;, nurat_mul, 1);
+    rb_objc_define_method(rb_cRational, &quot;/&quot;, nurat_div, 1);
+    rb_objc_define_method(rb_cRational, &quot;quo&quot;, nurat_div, 1);
+    rb_objc_define_method(rb_cRational, &quot;fdiv&quot;, nurat_fdiv, 1);
+    rb_objc_define_method(rb_cRational, &quot;**&quot;, nurat_expt, 1);
</ins><span class="cx"> 
</span><del>-    rb_define_method(rb_cRational, &quot;+&quot;, nurat_add, 1);
-    rb_define_method(rb_cRational, &quot;-&quot;, nurat_sub, 1);
-    rb_define_method(rb_cRational, &quot;*&quot;, nurat_mul, 1);
-    rb_define_method(rb_cRational, &quot;/&quot;, nurat_div, 1);
-    rb_define_method(rb_cRational, &quot;quo&quot;, nurat_div, 1);
-    rb_define_method(rb_cRational, &quot;fdiv&quot;, nurat_fdiv, 1);
-    rb_define_method(rb_cRational, &quot;**&quot;, nurat_expt, 1);
</del><ins>+    rb_objc_define_method(rb_cRational, &quot;&lt;=&gt;&quot;, nurat_cmp, 1);
+    rb_objc_define_method(rb_cRational, &quot;==&quot;, nurat_eqeq_p, 1);
+    rb_objc_define_method(rb_cRational, &quot;coerce&quot;, nurat_coerce, 1);
</ins><span class="cx"> 
</span><del>-    rb_define_method(rb_cRational, &quot;&lt;=&gt;&quot;, nurat_cmp, 1);
-    rb_define_method(rb_cRational, &quot;==&quot;, nurat_equal_p, 1);
-    rb_define_method(rb_cRational, &quot;coerce&quot;, nurat_coerce, 1);
-
-    rb_define_method(rb_cRational, &quot;div&quot;, nurat_idiv, 1);
-#if NUBY
</del><ins>+#if 0 /* NUBY */
</ins><span class="cx">     rb_define_method(rb_cRational, &quot;//&quot;, nurat_idiv, 1);
</span><span class="cx"> #endif
</span><del>-    rb_define_method(rb_cRational, &quot;modulo&quot;, nurat_mod, 1);
-    rb_define_method(rb_cRational, &quot;%&quot;, nurat_mod, 1);
-    rb_define_method(rb_cRational, &quot;divmod&quot;, nurat_divmod, 1);
</del><span class="cx"> 
</span><span class="cx"> #if 0
</span><span class="cx">     rb_define_method(rb_cRational, &quot;quot&quot;, nurat_quot, 1);
</span><del>-#endif
-    rb_define_method(rb_cRational, &quot;remainder&quot;, nurat_rem, 1);
-#if 0
</del><span class="cx">     rb_define_method(rb_cRational, &quot;quotrem&quot;, nurat_quotrem, 1);
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    rb_define_method(rb_cRational, &quot;abs&quot;, nurat_abs, 0);
-
</del><span class="cx"> #if 0
</span><span class="cx">     rb_define_method(rb_cRational, &quot;rational?&quot;, nurat_true, 0);
</span><span class="cx">     rb_define_method(rb_cRational, &quot;exact?&quot;, nurat_true, 0);
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    rb_define_method(rb_cRational, &quot;floor&quot;, nurat_floor, 0);
-    rb_define_method(rb_cRational, &quot;ceil&quot;, nurat_ceil, 0);
-    rb_define_method(rb_cRational, &quot;truncate&quot;, nurat_truncate, 0);
-    rb_define_method(rb_cRational, &quot;round&quot;, nurat_round, 0);
</del><ins>+    rb_objc_define_method(rb_cRational, &quot;floor&quot;, nurat_floor_n, -1);
+    rb_objc_define_method(rb_cRational, &quot;ceil&quot;, nurat_ceil_n, -1);
+    rb_objc_define_method(rb_cRational, &quot;truncate&quot;, nurat_truncate_n, -1);
+    rb_objc_define_method(rb_cRational, &quot;round&quot;, nurat_round_n, -1);
</ins><span class="cx"> 
</span><del>-    rb_define_method(rb_cRational, &quot;to_i&quot;, nurat_truncate, 0);
-    rb_define_method(rb_cRational, &quot;to_f&quot;, nurat_to_f, 0);
-    rb_define_method(rb_cRational, &quot;to_r&quot;, nurat_to_r, 0);
</del><ins>+    rb_objc_define_method(rb_cRational, &quot;to_i&quot;, nurat_truncate, 0);
+    rb_objc_define_method(rb_cRational, &quot;to_f&quot;, nurat_to_f, 0);
+    rb_objc_define_method(rb_cRational, &quot;to_r&quot;, nurat_to_r, 0);
</ins><span class="cx"> 
</span><del>-    rb_define_method(rb_cRational, &quot;hash&quot;, nurat_hash, 0);
</del><ins>+    rb_objc_define_method(rb_cRational, &quot;hash&quot;, nurat_hash, 0);
</ins><span class="cx"> 
</span><del>-    rb_define_method(rb_cRational, &quot;to_s&quot;, nurat_to_s, 0);
-    rb_define_method(rb_cRational, &quot;inspect&quot;, nurat_inspect, 0);
</del><ins>+    rb_objc_define_method(rb_cRational, &quot;to_s&quot;, nurat_to_s, 0);
+    rb_objc_define_method(rb_cRational, &quot;inspect&quot;, nurat_inspect, 0);
</ins><span class="cx"> 
</span><del>-    rb_define_method(rb_cRational, &quot;marshal_dump&quot;, nurat_marshal_dump, 0);
-    rb_define_method(rb_cRational, &quot;marshal_load&quot;, nurat_marshal_load, 1);
</del><ins>+    rb_objc_define_method(rb_cRational, &quot;marshal_dump&quot;, nurat_marshal_dump, 0);
+    rb_objc_define_method(rb_cRational, &quot;marshal_load&quot;, nurat_marshal_load, 1);
</ins><span class="cx"> 
</span><span class="cx">     /* --- */
</span><span class="cx"> 
</span><del>-    rb_define_method(rb_cInteger, &quot;gcd&quot;, rb_gcd, 1);
-    rb_define_method(rb_cInteger, &quot;lcm&quot;, rb_lcm, 1);
-    rb_define_method(rb_cInteger, &quot;gcdlcm&quot;, rb_gcdlcm, 1);
</del><ins>+    rb_objc_define_method(rb_cInteger, &quot;gcd&quot;, rb_gcd, 1);
+    rb_objc_define_method(rb_cInteger, &quot;lcm&quot;, rb_lcm, 1);
+    rb_objc_define_method(rb_cInteger, &quot;gcdlcm&quot;, rb_gcdlcm, 1);
</ins><span class="cx"> 
</span><del>-    rb_define_method(rb_cNilClass, &quot;to_r&quot;, nilclass_to_r, 0);
-    rb_define_method(rb_cInteger, &quot;to_r&quot;, integer_to_r, 0);
-    rb_define_method(rb_cFloat, &quot;to_r&quot;, float_to_r, 0);
</del><ins>+    rb_objc_define_method(rb_cNumeric, &quot;numerator&quot;, numeric_numerator, 0);
+    rb_objc_define_method(rb_cNumeric, &quot;denominator&quot;, numeric_denominator, 0);
</ins><span class="cx"> 
</span><ins>+    rb_objc_define_method(rb_cInteger, &quot;numerator&quot;, integer_numerator, 0);
+    rb_objc_define_method(rb_cInteger, &quot;denominator&quot;, integer_denominator, 0);
+
+    rb_objc_define_method(rb_cFloat, &quot;numerator&quot;, float_numerator, 0);
+    rb_objc_define_method(rb_cFloat, &quot;denominator&quot;, float_denominator, 0);
+
+    rb_objc_define_method(rb_cNilClass, &quot;to_r&quot;, nilclass_to_r, 0);
+    rb_objc_define_method(rb_cInteger, &quot;to_r&quot;, integer_to_r, 0);
+    rb_objc_define_method(rb_cFloat, &quot;to_r&quot;, float_to_r, 0);
+
</ins><span class="cx">     make_patterns();
</span><span class="cx"> 
</span><del>-    rb_define_method(rb_cString, &quot;to_r&quot;, string_to_r, 0);
</del><ins>+    rb_objc_define_method(rb_cString, &quot;to_r&quot;, string_to_r, 0);
</ins><span class="cx"> 
</span><del>-    rb_define_singleton_method(rb_cRational, &quot;convert&quot;, nurat_s_convert, -1);
-//    rb_funcall(rb_cRational, rb_intern(&quot;private_class_method&quot;), 1,
-//               ID2SYM(rb_intern(&quot;convert&quot;)));
</del><ins>+    rb_objc_define_method(*(VALUE *)rb_cRational, &quot;convert&quot;, nurat_s_convert, -1);
+//    rb_define_private_method(CLASS_OF(rb_cRational), &quot;convert&quot;, nurat_s_convert, -1);
+}
</ins><span class="cx"> 
</span><del>-    rb_include_module(rb_cRational, rb_mPrecision);
-    rb_define_singleton_method(rb_cRational, &quot;induced_from&quot;,
-                               nurat_s_induced_from, 1);
-}
</del><ins>+/*
+Local variables:
+c-file-style: &quot;ruby&quot;
+End:
+*/
</ins></span></pre>
</div>
</div>

</body>
</html>