[前][次][番号順一覧][スレッド一覧]

ruby-changes:4293

From: ko1@a...
Date: Sun, 16 Mar 2008 09:25:19 +0900 (JST)
Subject: [ruby-changes:4293] tadf - Ruby:r15783 (trunk): both complex and rational are now builtin classes.

tadf	2008-03-16 09:23:43 +0900 (Sun, 16 Mar 2008)

  New Revision: 15783

  Added files:
    trunk/complex.c
    trunk/rational.c
    trunk/test/ruby/test_complex.rb
    trunk/test/ruby/test_rational.rb
  Modified files:
    trunk/ChangeLog
    trunk/bignum.c
    trunk/common.mk
    trunk/configure.in
    trunk/gc.c
    trunk/include/ruby/intern.h
    trunk/include/ruby/ruby.h
    trunk/inits.c
    trunk/lib/complex.rb
    trunk/lib/mathn.rb
    trunk/lib/rational.rb
    trunk/numeric.c

  Log:
    both complex and rational are now builtin classes.
    


  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/numeric.c?r1=15783&r2=15782&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/include/ruby/ruby.h?r1=15783&r2=15782&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/test/ruby/test_complex.rb?revision=15783&view=markup
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/test/ruby/test_complex.rb?r1=15783&r2=15782&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/complex.rb?r1=15783&r2=15782&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/complex.c?revision=15783&view=markup
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/complex.c?r1=15783&r2=15782&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ChangeLog?r1=15783&r2=15782&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/test/ruby/test_rational.rb?revision=15783&view=markup
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/test/ruby/test_rational.rb?r1=15783&r2=15782&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rational.rb?r1=15783&r2=15782&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/bignum.c?r1=15783&r2=15782&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/gc.c?r1=15783&r2=15782&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/mathn.rb?r1=15783&r2=15782&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/inits.c?r1=15783&r2=15782&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/rational.c?revision=15783&view=markup
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/rational.c?r1=15783&r2=15782&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/configure.in?r1=15783&r2=15782&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/include/ruby/intern.h?r1=15783&r2=15782&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/common.mk?r1=15783&r2=15782&diff_format=u

Index: complex.c
===================================================================
--- complex.c	(revision 0)
+++ complex.c	(revision 15783)
@@ -0,0 +1,1533 @@
+/*
+  nucomp_core.c: Coded by Tadayoshi Funaba 2008
+
+  This implementation is based on Keiju Ishitsuka's Complex library
+  which is written in ruby.
+*/
+
+#include "ruby.h"
+#include <math.h>
+
+#define NDEBUG
+#include <assert.h>
+
+#ifndef COMPLEX_NAME
+#define COMPLEX_NAME "Complex"
+#endif
+
+#define ZERO INT2FIX(0)
+#define ONE INT2FIX(1)
+#define TWO INT2FIX(2)
+
+VALUE rb_cComplex;
+
+static ID id_Unify, id_abs, id_abs2, id_arg, id_atan2_bang, id_cmp,
+  id_coerce, 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;
+
+#define f_add(x,y) rb_funcall(x, '+', 1, y)
+#define f_div(x,y) rb_funcall(x, '/', 1, y)
+#define f_gt_p(x,y) rb_funcall(x, '>', 1, y)
+#define f_lt_p(x,y) rb_funcall(x, '<', 1, y)
+#define f_mod(x,y) rb_funcall(x, '%', 1, y)
+#define f_mul(x,y) rb_funcall(x, '*', 1, y)
+#define f_sub(x,y) rb_funcall(x, '-', 1, y)
+#define f_xor(x,y) rb_funcall(x, '^', 1, y)
+
+#define f_abs(x) rb_funcall(x, id_abs, 0)
+#define f_abs2(x) rb_funcall(x, id_abs2, 0)
+#define f_arg(x) rb_funcall(x, id_arg, 0)
+#define f_conjugate(x) rb_funcall(x, id_conjugate, 0)
+#define f_denominator(x) rb_funcall(x, id_denominator, 0)
+#define f_exact_p(x) rb_funcall(x, id_exact_p, 0)
+#define f_floor(x) rb_funcall(x, id_floor, 0)
+#define f_negate(x) rb_funcall(x, id_negate, 0)
+#define f_numerator(x) rb_funcall(x, id_numerator, 0)
+#define f_polar(x) rb_funcall(x, id_polar, 0)
+#define f_scalar_p(x) rb_funcall(x, id_scalar_p, 0)
+#define f_to_f(x) rb_funcall(x, id_to_f, 0)
+#define f_to_i(x) rb_funcall(x, id_to_i, 0)
+#define f_to_r(x) rb_funcall(x, id_to_r, 0)
+#define f_to_s(x) rb_funcall(x, id_to_s, 0)
+#define f_truncate(x) rb_funcall(x, id_truncate, 0)
+#define f_cmp(x,y) rb_funcall(x, id_cmp, 1, y)
+#define f_coerce(x,y) rb_funcall(x, id_coerce, 1, y)
+#define f_divmod(x,y) rb_funcall(x, id_divmod, 1, y)
+#define f_equal_p(x,y) rb_funcall(x, id_equal_p, 1, y)
+#define f_expt(x,y) rb_funcall(x, id_expt, 1, y)
+#define f_idiv(x,y) rb_funcall(x, id_idiv, 1, y)
+#define f_inspect(x) rb_funcall(x, id_inspect, 0)
+#define f_quo(x,y) rb_funcall(x, id_quo, 1, y)
+
+#if 0
+#define m_cos(x) rb_funcall(rb_mMath, id_cos, 1, x)
+#define m_exp_bang(x) rb_funcall(rb_mMath, id_exp_bang, 1, x)
+#define m_log_bang(x) rb_funcall(rb_mMath, id_log_bang, 1, x)
+#define m_sin(x) rb_funcall(rb_mMath, id_sin, 1, x)
+#define m_sqrt(x) rb_funcall(rb_mMath, id_sqrt, 1, x)
+#define m_atan2_bang(x,y) rb_funcall(rb_mMath, id_atan2_bang, 2, x, y)
+#define m_hypot(x,y) rb_funcall(rb_mMath, id_hypot, 2, x, y)
+#endif
+
+#define f_negative_p(x) f_lt_p(x, ZERO)
+#define f_zero_p(x) f_equal_p(x, ZERO)
+#define f_one_p(x) f_equal_p(x, ONE)
+#define f_kind_of_p(x,c) rb_obj_is_kind_of(x, c)
+#define k_numeric_p(x) f_kind_of_p(x, rb_cNumeric)
+#define k_integer_p(x) f_kind_of_p(x, rb_cInteger)
+#define k_float_p(x) f_kind_of_p(x, rb_cFloat)
+#define k_rational_p(x) f_kind_of_p(x, rb_cRational)
+#define k_complex_p(x) f_kind_of_p(x, rb_cComplex)
+
+#define f_boolcast(x) ((x) ? Qtrue : Qfalse)
+
+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;
+  }
+}
+
+static VALUE
+nucomp_s_generic_p(VALUE klass, VALUE x)
+{
+  return f_generic_p(x);
+}
+
+#define get_dat1(x) \
+  struct RComplex *dat;\
+  dat = ((struct RComplex *)(x))
+
+#define get_dat2(x,y) \
+  struct RComplex *adat, *bdat;\
+  adat = ((struct RComplex *)(x));\
+  bdat = ((struct RComplex *)(y))
+
+inline static VALUE
+nucomp_s_new_internal(VALUE klass, VALUE real, VALUE image)
+{
+  NEWOBJ(obj, struct RComplex);
+  OBJSETUP(obj, klass, T_COMPLEX);
+
+  obj->real = real;
+  obj->image = image;
+
+  return (VALUE)obj;
+}
+
+static VALUE
+nucomp_s_alloc(VALUE klass)
+{
+  return nucomp_s_new_internal(klass, ZERO, ZERO);
+}
+
+static VALUE
+nucomp_s_new_bang(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE real, image;
+
+  switch (rb_scan_args(argc, argv, "11", &real, &image)) {
+  case 1:
+    if (!k_numeric_p(real))
+      real = f_to_i(real);
+    image = ZERO;
+    break;
+  default:
+    if (!k_numeric_p(real))
+      real = f_to_i(real);
+    if (!k_numeric_p(image))
+      image = f_to_i(image);
+    break;
+  }
+
+  return nucomp_s_new_internal(klass, real, image);
+}
+
+inline static VALUE
+f_complex_new_bang1(VALUE klass, VALUE x)
+{
+  return nucomp_s_new_internal(klass, x, ZERO);
+}
+
+inline static VALUE
+f_complex_new_bang2(VALUE klass, VALUE x, VALUE y)
+{
+  return nucomp_s_new_internal(klass, x, y);
+}
+
+#define f_unify_p(klass) rb_const_defined(klass, id_Unify)
+
+inline static VALUE
+nucomp_s_canonicalize_internal(VALUE klass, VALUE real, VALUE image)
+{
+#define CL_CANON
+#ifdef CL_CANON
+  if (f_zero_p(image) && f_unify_p(klass) &&
+      !k_float_p(real) && !k_float_p(image))
+    return real;
+#else
+  if (f_zero_p(image) && f_unify_p(klass))
+    return real;
+#endif
+  else if (f_scalar_p(real) && f_scalar_p(image))
+    return nucomp_s_new_internal(klass, real, image);
+  else if (f_scalar_p(real)) {
+    get_dat1(image);
+
+    return nucomp_s_new_internal(klass,
+				 f_sub(real, dat->image),
+				 f_add(ZERO, dat->real));
+  } else if (f_scalar_p(image)) {
+    get_dat1(real);
+
+    return nucomp_s_new_internal(klass,
+				 dat->real,
+				 f_add(dat->image, image));
+  } else {
+    get_dat2(real, image);
+
+    return nucomp_s_new_internal(klass,
+				 f_sub(adat->real, bdat->image),
+				 f_add(adat->image, bdat->real));
+  }
+}
+
+static VALUE
+nucomp_s_canonicalize(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE real, image;
+
+  switch (rb_scan_args(argc, argv, "11", &real, &image)) {
+  case 1:
+    image = ZERO;
+    break;
+  }
+
+  switch (TYPE(real)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+  case T_FLOAT:
+    break;
+  default:
+    if (!k_rational_p(real))
+      rb_raise(rb_eArgError, "not a real");
+  }
+
+  switch (TYPE(image)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+  case T_FLOAT:
+    break;
+  default:
+    if (!k_rational_p(image))
+      rb_raise(rb_eArgError, "not a real");
+  }
+
+  return nucomp_s_canonicalize_internal(klass, real, image);
+}
+
+static VALUE
+nucomp_s_new(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE real, image;
+
+  switch (rb_scan_args(argc, argv, "11", &real, &image)) {
+  case 1:
+    image = ZERO;
+    break;
+  }
+
+  switch (TYPE(real)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+  case T_FLOAT:
+    break;
+  default:
+    if (!k_rational_p(real))
+      rb_raise(rb_eArgError, "not a real");
+  }
+
+  switch (TYPE(image)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+  case T_FLOAT:
+    break;
+  default:
+    if (!k_rational_p(image))
+      rb_raise(rb_eArgError, "not a real");
+  }
+
+  return nucomp_s_canonicalize_internal(klass, real, image);
+}
+
+inline static VALUE
+f_complex_new1(VALUE klass, VALUE x)
+{
+  assert(!k_complex_p(x));
+  return nucomp_s_canonicalize_internal(klass, x, ZERO);
+}
+
+inline static VALUE
+f_complex_new2(VALUE klass, VALUE x, VALUE y)
+{
+  assert(!k_complex_p(x));
+  return nucomp_s_canonicalize_internal(klass, x, y);
+}
+
+static VALUE
+nucomp_f_complex(int argc, VALUE *argv, VALUE klass)
+{
+  return rb_funcall2(rb_cComplex, id_convert, argc, argv);
+}
+
+#if 1
+/* the following code is copied from math.c */
+
+#include <errno.h>
+
+#define Need_Float(x) (x) = rb_Float(x)
+#define Need_Float2(x,y) do {\
+    Need_Float(x);\
+    Need_Float(y);\
+} while (0)
+
+static void
+domain_check(double x, char *msg)
+{
+  while(1) {
+    if (errno) {
+      rb_sys_fail(msg);
+    }
+    if (isnan(x)) {
+#if defined(EDOM)
+      errno = EDOM;
+#elif defined(ERANGE)
+      errno = ERANGE;
+#endif
+      continue;
+    }
+    break;
+  }
+}
+
+static VALUE
+m_cos_bang(VALUE x)
+{
+  Need_Float(x);
+  return DOUBLE2NUM(cos(RFLOAT_VALUE(x)));
+}
+
+static VALUE m_cos_bang(VALUE);
+static VALUE m_cosh_bang(VALUE);
+static VALUE m_sin_bang(VALUE);
+static VALUE m_sinh_bang(VALUE);
+
+static VALUE
+m_cos(VALUE x)
+{
+  get_dat1(x);
+
+  if (f_generic_p(x))
+    return m_cos_bang(x);
+  else
+    return f_complex_new2(rb_cComplex,
+			  f_mul(m_cos_bang(dat->real),
+				m_cosh_bang(dat->image)),
+			  f_mul(f_negate(m_sin_bang(dat->real)),
+				m_sinh_bang(dat->image)));
+}
+
+#ifndef HAVE_COSH
+double
+cosh(double x)
+{
+  return (exp(x) + exp(-x)) / 2;
+}
+#endif
+
+static VALUE
+m_cosh_bang(VALUE x)
+{
+  Need_Float(x);
+  return DOUBLE2NUM(cosh(RFLOAT_VALUE(x)));
+}
+
+static VALUE
+m_exp_bang(VALUE x)
+{
+  Need_Float(x);
+  return DOUBLE2NUM(exp(RFLOAT_VALUE(x)));
+}
+
+static VALUE
+m_log_bang(VALUE x)
+{
+  double d;
+
+  Need_Float(x);
+  errno = 0;
+  d = log(RFLOAT_VALUE(x));
+  domain_check(d, "log");
+  return DOUBLE2NUM(d);
+}
+
+static VALUE
+m_sin_bang(VALUE x)
+{
+  Need_Float(x);
+  return DOUBLE2NUM(sin(RFLOAT_VALUE(x)));
+}
+
+static VALUE
+m_sin(VALUE x)
+{
+  get_dat1(x);
+
+  if (f_generic_p(x))
+    return m_sin_bang(x);
+  else
+    return f_complex_new2(rb_cComplex,
+			  f_mul(m_sin_bang(dat->real),
+				m_cosh_bang(dat->image)),
+			  f_mul(m_cos_bang(dat->real),
+				m_sinh_bang(dat->image)));
+}
+
+#ifndef HAVE_SINH
+double
+sinh(double x)
+{
+  return (exp(x) - exp(-x)) / 2;
+}
+#endif
+
+static VALUE
+m_sinh_bang(VALUE x)
+{
+  Need_Float(x);
+  return DOUBLE2NUM(sinh(RFLOAT_VALUE(x)));
+}
+
+static VALUE
+m_sqrt_bang(VALUE x)
+{
+  double d;
+
+  Need_Float(x);
+  errno = 0;
+  d = sqrt(RFLOAT_VALUE(x));
+  domain_check(d, "sqrt");
+  return DOUBLE2NUM(d);
+}
+
+static VALUE
+m_sqrt(VALUE x)
+{
+  if (f_generic_p(x)) {
+    if (!f_negative_p(x))
+      return m_sqrt_bang(x);
+    else
+      return f_complex_new2(rb_cComplex, ZERO, m_sqrt_bang(f_negate(x)));
+  } else {
+    get_dat1(x);
+
+    if (f_negative_p(dat->image))
+      return f_conjugate(m_sqrt(f_conjugate(x)));
+    else {
+      VALUE a = f_abs(x);
+      return f_complex_new2(rb_cComplex,
+			    m_sqrt_bang(f_div(f_add(a, dat->real), TWO)),
+			    m_sqrt_bang(f_div(f_sub(a, dat->real), TWO)));
+    }
+  }
+}
+
+static VALUE
+m_atan2_bang(VALUE y, VALUE x)
+{
+  Need_Float2(y, x);
+  return DOUBLE2NUM(atan2(RFLOAT_VALUE(y), RFLOAT_VALUE(x)));
+}
+
+static VALUE
+m_hypot(VALUE x, VALUE y)
+{
+  Need_Float2(x, y);
+  return DOUBLE2NUM(hypot(RFLOAT_VALUE(x), RFLOAT_VALUE(y)));
+}
+#endif
+
+static VALUE
+nucomp_s_polar(VALUE klass, VALUE abs, VALUE arg)
+{
+  return f_complex_new2(klass,
+			f_mul(abs, m_cos(arg)),
+			f_mul(abs, m_sin(arg)));
+}
+
+static VALUE
+nucomp_real(VALUE self)
+{
+  get_dat1(self);
+  return dat->real;
+}
+
+static VALUE
+nucomp_image(VALUE self)
+{
+  get_dat1(self);
+  return dat->image;
+}
+
+static VALUE
+nucomp_add(VALUE self, VALUE other)
+{
+  switch (TYPE(other)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+  case T_FLOAT:
+  case T_RATIONAL:
+    {
+      get_dat1(self);
+
+      return f_complex_new2(CLASS_OF(self),
+			    f_add(dat->real, other), dat->image);
+    }
+  case T_COMPLEX:
+    {
+      VALUE real, image;
+
+      get_dat2(self, other);
+
+      real = f_add(adat->real, bdat->real);
+      image = f_add(adat->image, bdat->image);
+
+      return f_complex_new2(CLASS_OF(self), real, image);
+    }
+  default:
+    {
+      VALUE a = f_coerce(other, self);
+      return f_add(RARRAY_PTR(a)[0], RARRAY_PTR(a)[1]);
+    }
+  }
+}
+
+static VALUE
+nucomp_sub(VALUE self, VALUE other)
+{
+  switch (TYPE(other)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+  case T_FLOAT:
+  case T_RATIONAL:
+    {
+      get_dat1(self);
+
+      return f_complex_new2(CLASS_OF(self),
+			    f_sub(dat->real, other), dat->image);
+    }
+  case T_COMPLEX:
+    {
+      VALUE real, image;
+
+      get_dat2(self, other);
+
+      real = f_sub(adat->real, bdat->real);
+      image = f_sub(adat->image, bdat->image);
+
+      return f_complex_new2(CLASS_OF(self), real, image);
+    }
+  default:
+    {
+      VALUE a = f_coerce(other, self);
+      return f_add(RARRAY_PTR(a)[0], RARRAY_PTR(a)[1]);
+    }
+  }
+}
+
+static VALUE
+nucomp_mul(VALUE self, VALUE other)
+{
+  switch (TYPE(other)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+  case T_FLOAT:
+  case T_RATIONAL:
+    {
+      get_dat1(self);
+
+      return f_complex_new2(CLASS_OF(self),
+			    f_mul(dat->real, other),
+			    f_mul(dat->image, other));
+    }
+  case T_COMPLEX:
+    {
+      VALUE real, image;
+
+      get_dat2(self, other);
+
+      real = f_sub(f_mul(adat->real, bdat->real),
+		   f_mul(adat->image, bdat->image));
+      image = f_add(f_mul(adat->real, bdat->image),
+		    f_mul(adat->image, bdat->real));
+
+      return f_complex_new2(CLASS_OF(self), real, image);
+    }
+  default:
+    {
+      VALUE a = f_coerce(other, self);
+      return f_mul(RARRAY_PTR(a)[0], RARRAY_PTR(a)[1]);
+    }
+  }
+}
+
+static VALUE
+nucomp_div(VALUE self, VALUE other)
+{
+  switch (TYPE(other)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+  case T_FLOAT:
+  case T_RATIONAL:
+    {
+      get_dat1(self);
+
+      return f_complex_new2(CLASS_OF(self),
+			    f_div(dat->real, other),
+			    f_div(dat->image, other));
+    }
+  case T_COMPLEX:
+    return f_div(f_mul(self, f_conjugate(other)), f_abs2(other));
+  default:
+    {
+      VALUE a = f_coerce(other, self);
+      return f_div(RARRAY_PTR(a)[0], RARRAY_PTR(a)[1]);
+    }
+  }
+}
+
+static VALUE
+nucomp_rdiv(VALUE self, VALUE other)
+{
+  get_dat1(self);
+
+  return f_div(f_complex_new2(CLASS_OF(self),
+			      f_to_r(dat->real),
+			      f_to_r(dat->image)), other);
+}
+
+static VALUE
+nucomp_fdiv(VALUE self, VALUE other)
+{
+  get_dat1(self);
+
+  return f_div(f_complex_new2(CLASS_OF(self),
+			      f_to_f(dat->real),
+			      f_to_f(dat->image)), other);
+}
+
+static VALUE
+nucomp_expt(VALUE self, VALUE other)
+{
+  if (f_zero_p(other))
+    return f_complex_new_bang1(CLASS_OF(self), ONE);
+
+  if (k_rational_p(other) && f_one_p(f_denominator(other)))
+    other = f_numerator(other); /* good? */
+
+  switch (TYPE(other)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+    if (f_gt_p(other, ZERO)) {
+      VALUE x, z, n;
+
+      x = self;
+      z = x;
+      n = f_sub(other, ONE);
+
+      while (!f_zero_p(n)) {
+	VALUE a;
+
+	while (a = f_divmod(n, TWO),
+	       f_zero_p(RARRAY_PTR(a)[1])) {
+	  get_dat1(x);
+
+	  x = f_complex_new2(CLASS_OF(self),
+			     f_sub(f_mul(dat->real, dat->real),
+				   f_mul(dat->image, dat->image)),
+			     f_mul(f_mul(TWO, dat->real), dat->image));
+	  n = RARRAY_PTR(a)[0];
+	}
+	z = f_mul(z, x);
+	n = f_sub(n, ONE);
+      }
+      return z;
+    } else {
+      return f_expt(f_div(f_to_r(ONE), self), f_negate(other));
+    }
+  case T_FLOAT:
+  case T_RATIONAL:
+    {
+      VALUE a, r, theta;
+
+      a = f_polar(self);
+      r = RARRAY_PTR(a)[0];
+      theta = RARRAY_PTR(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;
+
+      get_dat1(other);
+
+      a = f_polar(self);
+      r = RARRAY_PTR(a)[0];
+      theta = RARRAY_PTR(a)[1];
+
+      ore = dat->real;
+      oim = dat->image;
+      nr = m_exp_bang(f_sub(f_mul(ore, m_log_bang(r)),
+			    f_mul(oim, theta)));
+      ntheta = f_add(f_mul(theta, ore), f_mul(oim, m_log_bang(r)));
+      return nucomp_s_polar(CLASS_OF(self), nr, ntheta);
+    }
+  default:
+    {
+      VALUE a = f_coerce(other, self);
+      return f_div(RARRAY_PTR(a)[0], RARRAY_PTR(a)[1]);
+    }
+  }
+}
+
+static VALUE
+nucomp_equal_p(VALUE self, VALUE other)
+{
+  switch (TYPE(other)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+  case T_FLOAT:
+  case T_RATIONAL:
+    {
+      get_dat1(self);
+
+      return f_boolcast(f_equal_p(dat->real, other) && f_zero_p(dat->image));
+    }
+  case T_COMPLEX:
+    {
+      get_dat2(self, other);
+
+      return f_boolcast(f_equal_p(adat->real, bdat->real) &&
+			f_equal_p(adat->image, bdat->image));
+    }
+  default:
+    return f_equal_p(other, self);
+  }
+}
+
+static VALUE
+nucomp_coerce(VALUE self, VALUE other)
+{
+  switch (TYPE(other)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+  case T_FLOAT:
+  case T_RATIONAL:
+    return rb_assoc_new(f_complex_new_bang1(CLASS_OF(self), other), self);
+  }
+
+  rb_raise(rb_eTypeError, "%s can't be coerced into %s",
+	   rb_obj_classname(other), rb_obj_classname(self));
+  return Qnil;
+}
+
+static VALUE
+nucomp_abs(VALUE self)
+{
+  get_dat1(self);
+  return m_sqrt(f_add(f_mul(dat->real, dat->real),
+		      f_mul(dat->image, dat->image)));
+}
+
+static VALUE
+nucomp_abs2(VALUE self)
+{
+  get_dat1(self);
+  return f_add(f_mul(dat->real, dat->real),
+	       f_mul(dat->image, dat->image));
+}
+
+static VALUE
+nucomp_arg(VALUE self)
+{
+  get_dat1(self);
+  return m_atan2_bang(dat->image, dat->real);
+}
+
+static VALUE
+nucomp_polar(VALUE self)
+{
+  return rb_assoc_new(f_abs(self), f_arg(self));
+}
+
+static VALUE
+nucomp_conjugate(VALUE self)
+{
+  get_dat1(self);
+  return f_complex_new2(CLASS_OF(self), dat->real, f_negate(dat->image));
+}
+
+static VALUE
+nucomp_real_p(VALUE self)
+{
+  return Qfalse;
+}
+
+static VALUE
+nucomp_complex_p(VALUE self)
+{
+  return Qtrue;
+}
+
+static VALUE
+nucomp_exact_p(VALUE self)
+{
+  get_dat1(self);
+  return f_boolcast(f_exact_p(dat->real) && f_exact_p(dat->image));
+}
+
+static VALUE
+nucomp_inexact_p(VALUE self)
+{
+  return f_boolcast(!nucomp_exact_p(self));
+}
+
+inline static long
+i_gcd(long x, long y)
+{
+  long b;
+
+  if (x < 0)
+    x = -x;
+  if (y < 0)
+    y = -y;
+
+  if (x == 0)
+    return y;
+  if (y == 0)
+    return x;
+
+  b = 0;
+  while ((x & 1) == 0 && (y & 1) == 0) {
+    b += 1;
+    x >>= 1;
+    y >>= 1;
+  }
+
+  while ((x & 1) == 0)
+    x >>= 1;
+
+  while ((y & 1) == 0)
+    y >>= 1;
+
+  while (x != y) {
+    if (y > x) {
+      long t;
+      t = x;
+      x = y;
+      y = t;
+    }
+    x -= y;
+    while ((x & 1) == 0)
+      x >>= 1;
+  }
+
+  return x << b;
+}
+
+inline static VALUE
+f_gcd(VALUE x, VALUE y)
+{
+  VALUE z;
+
+  if (FIXNUM_P(x) && FIXNUM_P(y))
+    return LONG2NUM(i_gcd(FIX2LONG(x), FIX2LONG(y)));
+
+  if (f_negative_p(x))
+    x = f_negate(x);
+  if (f_negative_p(y))
+    y = f_negate(y);
+
+  if (f_zero_p(x))
+    return y;
+  if (f_zero_p(y))
+    return x;
+
+  for (;;) {
+    if (FIXNUM_P(x)) {
+      if (FIX2INT(x) == 0)
+	return y;
+      if (FIXNUM_P(y))
+	return LONG2NUM(i_gcd(FIX2LONG(x), FIX2LONG(y)));
+    }
+    z = x;
+    x = f_mod(y, x);
+    y = z;
+  }
+  /* NOTREACHED */
+}
+
+static VALUE
+f_lcm(VALUE x, VALUE y)
+{
+  if (f_zero_p(x) || f_zero_p(y))
+    return ZERO;
+  else
+    return f_abs(f_mul(f_div(x, f_gcd(x, y)), y));
+}
+
+static VALUE
+nucomp_denominator(VALUE self)
+{
+  get_dat1(self);
+  return f_lcm(f_denominator(dat->real), f_denominator(dat->image));
+}
+
+static VALUE
+nucomp_numerator(VALUE self)
+{
+  VALUE cd;
+
+  get_dat1(self);
+
+  cd = f_denominator(self);
+  return f_complex_new2(CLASS_OF(self),
+			f_mul(f_numerator(dat->real),
+			      f_div(cd, f_denominator(dat->real))),
+			f_mul(f_numerator(dat->image),
+			      f_div(cd, f_denominator(dat->image))));
+}
+
+static VALUE
+nucomp_hash(VALUE self)
+{
+  get_dat1(self);
+  return f_xor(dat->real, dat->image);
+}
+
+#ifndef HAVE_SIGNBIT
+#ifdef signbit
+#define HAVE_SIGNBIT 1
+#endif
+#endif
+
+inline static VALUE
+f_signbit(VALUE x)
+{
+  switch (TYPE(x)) {
+  case T_FLOAT:
+#ifdef HAVE_SIGNBIT
+    return f_boolcast(signbit(RFLOAT_VALUE(x)));
+#else
+    {
+      char s[2];
+
+      (void)snprintf(s, sizeof s, "%.0f", RFLOAT_VALUE(x));
+
+      return f_boolcast(s[0] == '-');
+    }
+#endif
+  }
+  return f_negative_p(x);
+}
+
+inline static VALUE
+f_tzero_p(VALUE x)
+{
+  return f_boolcast(f_zero_p(x) && !f_signbit(x));
+}
+
+inline static VALUE
+f_tpositive_p(VALUE x)
+{
+  return f_boolcast(!f_signbit(x));
+}
+
+static VALUE
+nucomp_to_s(VALUE self)
+{
+  VALUE s, rezero, impos;
+
+  get_dat1(self);
+
+  rezero = f_tzero_p(dat->real);
+  impos = f_tpositive_p(dat->image);
+
+  if (rezero)
+    s = rb_str_new2("");
+  else {
+    s = f_to_s(dat->real);
+    rb_str_concat(s, rb_str_new2(!impos ? "-" : "+"));
+  }
+
+  if (k_rational_p(dat->image) &&
+      !f_one_p(f_denominator(dat->image))) {
+    rb_str_concat(s, rb_str_new2("("));
+    rb_str_concat(s, f_to_s(rezero ? dat->image : f_abs(dat->image)));
+    rb_str_concat(s, rb_str_new2(")i"));
+  } else {
+    rb_str_concat(s, f_to_s(rezero ? dat->image : f_abs(dat->image)));
+    rb_str_concat(s, rb_str_new2("i"));
+  }
+
+  return s;
+}
+
+static VALUE
+nucomp_inspect(VALUE self)
+{
+  VALUE s;
+
+  get_dat1(self);
+
+  s = rb_str_new2("Complex(");
+  rb_str_concat(s, f_inspect(dat->real));
+  rb_str_concat(s, rb_str_new2(", "));
+  rb_str_concat(s, f_inspect(dat->image));
+  rb_str_concat(s, rb_str_new2(")"));
+
+  return s;
+}
+
+static VALUE
+nucomp_marshal_dump(VALUE self)
+{
+  get_dat1(self);
+  return rb_assoc_new(dat->real, dat->image);
+}
+
+static VALUE
+nucomp_marshal_load(VALUE self, VALUE a)
+{
+  get_dat1(self);
+  dat->real = RARRAY_PTR(a)[0];
+  dat->image = RARRAY_PTR(a)[1];
+  return self;
+}
+
+/* --- */
+
+VALUE
+rb_complex_raw(VALUE x, VALUE y)
+{
+  return nucomp_s_new_internal(rb_cComplex, x, y);
+}
+
+VALUE
+rb_complex_new(VALUE x, VALUE y)
+{
+  return nucomp_s_canonicalize_internal(rb_cComplex, x, y);
+}
+
+static VALUE nucomp_s_convert(int argc, VALUE *argv, VALUE klass);
+
+VALUE
+rb_Complex(VALUE x, VALUE y)
+{
+  VALUE a[2];
+  a[0] = x;
+  a[1] = y;
+  return nucomp_s_convert(2, a, rb_cComplex);
+}
+
+static VALUE
+nucomp_scalar_p(VALUE self)
+{
+  return Qfalse;
+}
+
+static VALUE
+nucomp_to_i(VALUE self)
+{
+  get_dat1(self);
+
+  if (k_float_p(dat->image) || !f_zero_p(dat->image)) {
+    VALUE s = f_to_s(self);
+    rb_raise(rb_eRangeError, "can't convert %s into Integer",
+	     StringValuePtr(s));
+  }
+  return f_to_i(dat->real);
+}
+
+static VALUE
+nucomp_to_f(VALUE self)
+{
+  get_dat1(self);
+
+  if (k_float_p(dat->image) || !f_zero_p(dat->image)) {
+    VALUE s = f_to_s(self);
+    rb_raise(rb_eRangeError, "can't convert %s into Integer",
+	     StringValuePtr(s));
+  }
+  return f_to_f(dat->real);
+}
+
+static VALUE
+nucomp_to_r(VALUE self)
+{
+  get_dat1(self);
+
+  if (k_float_p(dat->image) || !f_zero_p(dat->image)) {
+    VALUE s = f_to_s(self);
+    rb_raise(rb_eRangeError, "can't convert %s into Integer",
+	     StringValuePtr(s));
+  }
+  return f_to_r(dat->real);
+}
+
+static VALUE
+nilclass_to_c(VALUE self)
+{
+  return rb_complex_new1(INT2FIX(0));
+}
+
+static VALUE
+numeric_to_c(VALUE self)
+{
+  return rb_complex_new1(self);
+}
+
+static VALUE comp_pat1, comp_pat2, a_slash, a_dot_and_an_e,
+  image_garbages_pat, null_string, underscores_pat, an_underscore;
+
+#define DIGITS "(?:\\d(?:_\\d|\\d)*)"
+#define NUMERATOR "(?:" DIGITS "?\\.)?" DIGITS "(?:[eE][-+]?" DIGITS ")?"
+#define DENOMINATOR "[-+]?" DIGITS
+#define NUMBER "[-+]?" NUMERATOR "(?:\\/" DENOMINATOR ")?"
+#define NUMBERNOS NUMERATOR "(?:\\/" DENOMINATOR ")?"
+#define PATTERN1 "\\A(" NUMBER "|\\(" NUMBER "\\))[iIjJ]"
+#define PATTERN2 "\\A(" NUMBER ")([-+](?:" NUMBERNOS "|\\(" NUMBER "\\))[iIjJ])?"
+
+static void
+make_patterns(void)
+{
+  static char *comp_pat1_source = PATTERN1;
+  static char *comp_pat2_source = PATTERN2;
+  static char *image_garbages_pat_source = "[+\\(\\)iIjJ]";
+  static char *underscores_pat_source = "_+";
+
+  comp_pat1 = rb_reg_new(comp_pat1_source, strlen(comp_pat1_source), 0);
+  rb_global_variable(&comp_pat1);
+
+  comp_pat2 = rb_reg_new(comp_pat2_source, strlen(comp_pat2_source), 0);
+  rb_global_variable(&comp_pat2);
+
+  a_slash = rb_str_new2("/");
+  rb_global_variable(&a_slash);
+
+  a_dot_and_an_e = rb_str_new2(".eE");
+  rb_global_variable(&a_dot_and_an_e);
+
+  image_garbages_pat = rb_reg_new(image_garbages_pat_source,
+				  strlen(image_garbages_pat_source), 0);
+  rb_global_variable(&image_garbages_pat);
+
+  null_string = rb_str_new2("");
+  rb_global_variable(&null_string);
+
+  underscores_pat = rb_reg_new(underscores_pat_source,
+			       strlen(underscores_pat_source), 0);
+  rb_global_variable(&underscores_pat);
+
+  an_underscore = rb_str_new2("_");
+  rb_global_variable(&an_underscore);
+}
+
+#define id_strip rb_intern("strip")
+#define f_strip(x) rb_funcall(x, id_strip, 0)
+
+#define id_match rb_intern("match")
+#define f_match(x,y) rb_funcall(x, id_match, 1, y)
+
+#define id_aref rb_intern("[]")
+#define f_aref(x,y) rb_funcall(x, id_aref, 1, y)
+
+#define id_post_match rb_intern("post_match")
+#define f_post_match(x) rb_funcall(x, id_post_match, 0)
+
+#define id_split rb_intern("split")
+#define f_split(x,y) rb_funcall(x, id_split, 1, y)
+
+#define id_include_p rb_intern("include?")
+#define f_include_p(x,y) rb_funcall(x, id_include_p, 1, y)
+
+#define id_count rb_intern("count")
+#define f_count(x,y) rb_funcall(x, id_count, 1, y)
+
+#define id_gsub_bang rb_intern("gsub!")
+#define f_gsub_bang(x,y,z) rb_funcall(x, id_gsub_bang, 2, y, z)
+
+static VALUE
+string_to_c_internal(VALUE self)
+{
+  VALUE s;
+
+  s = f_strip(self);
+
+  if (RSTRING_LEN(s) == 0)
+    return rb_assoc_new(Qnil, self);
+
+  {
+    VALUE m, sr, si, re, r, i;
+
+    m = f_match(comp_pat1, s);
+    if (!NIL_P(m)) {
+      sr = Qnil;
+      si = f_aref(m, INT2FIX(1));
+      re = f_post_match(m);
+    }
+    if (NIL_P(m)) {
+      m = f_match(comp_pat2, s);
+      if (NIL_P(m))
+	return rb_assoc_new(Qnil, self);
+      sr = f_aref(m, INT2FIX(1));
+      si = f_aref(m, INT2FIX(2));
+      re = f_post_match(m);
+    }
+    r = INT2FIX(0);
+    i = INT2FIX(0);
+    if (!NIL_P(sr)) {
+      if (f_include_p(sr, a_slash))
+	r = f_to_r(sr);
+      else if (f_gt_p(f_count(sr, a_dot_and_an_e), INT2FIX(0)))
+	r = f_to_f(sr);
+      else
+	r = f_to_i(sr);
+    }
+    if (!NIL_P(si)) {
+      f_gsub_bang(si, image_garbages_pat, null_string);
+      if (f_include_p(si, a_slash))
+	i = f_to_r(si);
+      else if (f_gt_p(f_count(si, a_dot_and_an_e), INT2FIX(0)))
+	i = f_to_f(si);
+      else
+	i = f_to_i(si);
+    }
+    return rb_assoc_new(rb_complex_new2(r, i), re);
+  }
+}
+
+static VALUE
+string_to_c_strict(VALUE self)
+{
+  VALUE a = string_to_c_internal(self);
+  if (NIL_P(RARRAY_PTR(a)[0]) || RSTRING_LEN(RARRAY_PTR(a)[1]) > 0) {
+    VALUE s = f_inspect(self);
+    rb_raise(rb_eArgError, "invalid value for Complex: %s",
+	     StringValuePtr(s));
+  }
+  return RARRAY_PTR(a)[0];
+}
+
+#define id_gsub rb_intern("gsub")
+#define f_gsub(x,y,z) rb_funcall(x, id_gsub, 2, y, z)
+
+static VALUE
+string_to_c(VALUE self)
+{
+  VALUE s = f_gsub(self, underscores_pat, an_underscore);
+  VALUE a = string_to_c_internal(s);
+  if (!NIL_P(RARRAY_PTR(a)[0]))
+    return RARRAY_PTR(a)[0];
+  return rb_complex_new1(INT2FIX(0));
+}
+
+static VALUE
+nucomp_s_convert(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE a1, a2;
+
+  a1 = Qnil;
+  a2 = Qnil;
+  rb_scan_args(argc, argv, "02", &a1, &a2);
+
+  switch (TYPE(a1)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+  case T_FLOAT:
+    break;
+  case T_STRING:
+    a1 = string_to_c_strict(a1);
+    break;
+  }
+
+  switch (TYPE(a2)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+  case T_FLOAT:
+    break;
+  case T_STRING:
+    a2 = string_to_c_strict(a2);
+    break;
+  }
+
+  switch (TYPE(a1)) {
+  case T_COMPLEX:
+    {
+      get_dat1(a1);
+
+      if (!k_float_p(dat->image) && f_zero_p(dat->image))
+	a1 = dat->real;
+    }
+  }
+
+  switch (TYPE(a2)) {
+  case T_COMPLEX:
+    {
+      get_dat1(a2);
+
+      if (!k_float_p(dat->image) && f_zero_p(dat->image))
+	a2 = dat->real;
+    }
+  }
+
+  switch (TYPE(a1)) {
+  case T_COMPLEX:
+    if (NIL_P(a2) || f_zero_p(a2))
+      return a1;
+  }
+
+  {
+    VALUE argv2[2];
+    argv2[0] = a1;
+    argv2[1] = a2;
+    return nucomp_s_new(argc, argv2, klass);
+  }
+}
+
+/* --- */
+
+#define id_Complex rb_intern("Complex")
+
+static VALUE
+numeric_re(VALUE self)
+{
+  return rb_Complex1(self);
+}
+
+static VALUE
+numeric_im(VALUE self)
+{
+  return rb_Complex2(ZERO, self);
+}
+
+static VALUE
+numeric_real(VALUE self)
+{
+  return self;
+}
+
+static VALUE
+numeric_image(VALUE self)
+{
+  return INT2FIX(0);
+}
+
+#define id_PI rb_intern("PI")
+
+static VALUE
+numeric_arg(VALUE self)
+{
+  if (!f_negative_p(self))
+    return INT2FIX(0);
+  return rb_const_get(rb_mMath, id_PI);
+}
+
+static VALUE
+numeric_polar(VALUE self)
+{
+  return rb_assoc_new(f_abs(self), f_arg(self));
+}
+
+static VALUE
+numeric_conjugate(VALUE self)
+{
+  return self;
+}
+
+void
+Init_Complex(void)
+{
+  assert(fprintf(stderr, "assert() is now active\n"));
+
+  id_Unify = rb_intern("Unify");
+  id_abs = rb_intern("abs");
+  id_abs2 = rb_intern("abs2");
+  id_arg = rb_intern("arg");
+  id_atan2_bang = rb_intern("atan2!");
+  id_cmp = rb_intern("<=>");
+  id_coerce = rb_intern("coerce");
+  id_conjugate = rb_intern("conjugate");
+  id_convert = rb_intern("convert");
+  id_cos = rb_intern("cos");
+  id_denominator = rb_intern("denominator");
+  id_divmod = rb_intern("divmod");
+  id_equal_p = rb_intern("==");
+  id_exact_p = rb_intern("exact?");
+  id_exp_bang = rb_intern("exp!");
+  id_expt = rb_intern("**");
+  id_floor = rb_intern("floor");
+  id_format = rb_intern("format");
+  id_hypot = rb_intern("hypot");
+  id_idiv = rb_intern("div");
+  id_inspect = rb_intern("inspect");
+  id_log_bang = rb_intern("log!");
+  id_negate = rb_intern("-@");
+  id_new = rb_intern("new");
+  id_new_bang = rb_intern("new!");
+  id_numerator = rb_intern("numerator");
+  id_polar = rb_intern("polar");
+  id_quo = rb_intern("quo");
+  id_scalar_p = rb_intern("scalar?");
+  id_sin = rb_intern("sin");
+  id_sqrt = rb_intern("sqrt");
+  id_to_f = rb_intern("to_f");
+  id_to_i = rb_intern("to_i");
+  id_to_r = rb_intern("to_r");
+  id_to_s = rb_intern("to_s");
+  id_truncate = rb_intern("truncate");
+
+  rb_cComplex = rb_define_class(COMPLEX_NAME, rb_cNumeric);
+
+  rb_define_alloc_func(rb_cComplex, nucomp_s_alloc);
+  rb_funcall(rb_cComplex, rb_intern("private_class_method"), 1,
+	     ID2SYM(rb_intern("allocate")));
+
+  rb_define_singleton_method(rb_cComplex, "generic?", nucomp_s_generic_p, 1);
+
+  rb_define_singleton_method(rb_cComplex, "new!", nucomp_s_new_bang, -1);
+  rb_funcall(rb_cComplex, rb_intern("private_class_method"), 1,
+	     ID2SYM(rb_intern("new!")));
+
+  rb_define_singleton_method(rb_cComplex, "new", nucomp_s_new, -1);
+  rb_funcall(rb_cComplex, rb_intern("private_class_method"), 1,
+	     ID2SYM(rb_intern("new")));
+
+#if 0
+  rb_define_singleton_method(rb_cComplex, "rect", nucomp_s_new, -1);
+  rb_define_singleton_method(rb_cComplex, "rectangular", nucomp_s_new, -1);
+#endif
+  rb_define_singleton_method(rb_cComplex, "polar", nucomp_s_polar, 2);
+
+  rb_define_global_function(COMPLEX_NAME, nucomp_f_complex, -1);
+
+  rb_undef_method(rb_cComplex, "<");
+  rb_undef_method(rb_cComplex, "<=");
+  rb_undef_method(rb_cComplex, "<=>");
+  rb_undef_method(rb_cComplex, ">");
+  rb_undef_method(rb_cComplex, ">=");
+  rb_undef_method(rb_cComplex, "between?");
+  rb_undef_method(rb_cComplex, "divmod");
+  rb_undef_method(rb_cComplex, "floor");
+  rb_undef_method(rb_cComplex, "ceil");
+  rb_undef_method(rb_cComplex, "modulo");
+  rb_undef_method(rb_cComplex, "round");
+  rb_undef_method(rb_cComplex, "step");
+  rb_undef_method(rb_cComplex, "truncate");
+
+#if NUBY
+  rb_undef_method(rb_cComplex, "//");
+#endif
+
+  rb_define_method(rb_cComplex, "real", nucomp_real, 0);
+  rb_define_method(rb_cComplex, "image", nucomp_image, 0);
+  rb_define_method(rb_cComplex, "imag", nucomp_image, 0);
+
+  rb_define_method(rb_cComplex, "+", nucomp_add, 1);
+  rb_define_method(rb_cComplex, "-", nucomp_sub, 1);
+  rb_define_method(rb_cComplex, "*", nucomp_mul, 1);
+  rb_define_method(rb_cComplex, "/", nucomp_div, 1);
+  rb_define_method(rb_cComplex, "quo", nucomp_rdiv, 1);
+  rb_define_method(rb_cComplex, "rdiv", nucomp_rdiv, 1);
+  rb_define_method(rb_cComplex, "fdiv", nucomp_rdiv, 1);
+  rb_define_method(rb_cComplex, "**", nucomp_expt, 1);
+
+  rb_define_method(rb_cComplex, "==", nucomp_equal_p, 1);
+  rb_define_method(rb_cComplex, "coerce", nucomp_coerce, 1);
+
+  rb_define_method(rb_cComplex, "abs", nucomp_abs, 0);
+#if 0
+  rb_define_method(rb_cComplex, "magnitude", nucomp_abs, 0);
+#endif
+  rb_define_method(rb_cComplex, "abs2", nucomp_abs2, 0);
+  rb_define_method(rb_cComplex, "arg", nucomp_arg, 0);
+  rb_define_method(rb_cComplex, "angle", nucomp_arg, 0);
+  rb_define_method(rb_cComplex, "polar", nucomp_polar, 0);
+  rb_define_method(rb_cComplex, "conjugate", nucomp_conjugate, 0);
+  rb_define_method(rb_cComplex, "conj", nucomp_conjugate, 0);
+#if 0
+  rb_define_method(rb_cComplex, "~", nucomp_conjugate, 0); /* gcc */
+#endif
+
+#if 0
+  rb_define_method(rb_cComplex, "real?", nucomp_real_p, 0);
+  rb_define_method(rb_cComplex, "complex?", nucomp_complex_p, 0);
+  rb_define_method(rb_cComplex, "exact?", nucomp_exact_p, 0);
+  rb_define_method(rb_cComplex, "inexact?", nucomp_inexact_p, 0);
+#endif
+
+  rb_define_method(rb_cComplex, "numerator", nucomp_numerator, 0);
+  rb_define_method(rb_cComplex, "denominator", nucomp_denominator, 0);
+
+  rb_define_method(rb_cComplex, "hash", nucomp_hash, 0);
+
+  rb_define_method(rb_cComplex, "to_s", nucomp_to_s, 0);
+  rb_define_method(rb_cComplex, "inspect", nucomp_inspect, 0);
+
+  rb_define_method(rb_cComplex, "marshal_dump", nucomp_marshal_dump, 0);
+  rb_define_method(rb_cComplex, "marshal_load", nucomp_marshal_load, 1);
+
+  /* --- */
+
+  rb_define_method(rb_cComplex, "scalar?", nucomp_scalar_p, 0);
+  rb_define_method(rb_cComplex, "to_i", nucomp_to_i, 0);
+  rb_define_method(rb_cComplex, "to_f", nucomp_to_f, 0);
+  rb_define_method(rb_cComplex, "to_r", nucomp_to_r, 0);
+  rb_define_method(rb_cNilClass, "to_c", nilclass_to_c, 0);
+  rb_define_method(rb_cNumeric, "to_c", numeric_to_c, 0);
+
+  make_patterns();
+
+  rb_define_method(rb_cString, "to_c", string_to_c, 0);
+
+  rb_define_singleton_method(rb_cComplex, "convert", nucomp_s_convert, -1);
+  rb_funcall(rb_cComplex, rb_intern("private_class_method"), 1,
+	     ID2SYM(rb_intern("convert")));
+
+  /* --- */
+
+  rb_define_method(rb_cNumeric, "re", numeric_re, 0);
+  rb_define_method(rb_cNumeric, "im", numeric_im, 0);
+  rb_define_method(rb_cNumeric, "real", numeric_real, 0);
+  rb_define_method(rb_cNumeric, "image", numeric_image, 0);
+  rb_define_method(rb_cNumeric, "imag", numeric_image, 0);
+  rb_define_method(rb_cNumeric, "arg", numeric_arg, 0);
+  rb_define_method(rb_cNumeric, "angle", numeric_arg, 0);
+  rb_define_method(rb_cNumeric, "polar", numeric_polar, 0);
+  rb_define_method(rb_cNumeric, "conjugate", numeric_conjugate, 0);
+  rb_define_method(rb_cNumeric, "conj", numeric_conjugate, 0);
+
+  rb_define_const(rb_cComplex, "I",
+		  f_complex_new_bang2(rb_cComplex, ZERO, ONE));
+}

Property changes on: complex.c
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Index: include/ruby/intern.h
===================================================================
--- include/ruby/intern.h	(revision 15782)
+++ include/ruby/intern.h	(revision 15783)
@@ -117,6 +117,26 @@
 VALUE rb_big_xor(VALUE, VALUE);
 VALUE rb_big_lshift(VALUE, VALUE);
 VALUE rb_big_rshift(VALUE, VALUE);
+/* rational.c */
+VALUE rb_rational_raw(VALUE, VALUE);
+#define rb_rational_raw1(x) rb_rational_raw(x, INT2FIX(1))
+#define rb_rational_raw2(x,y) rb_rational_raw(x, y)
+VALUE rb_rational_new(VALUE, VALUE);
+#define rb_rational_new1(x) rb_rational_new(x, INT2FIX(1))
+#define rb_rational_new2(x,y) rb_rational_new(x, y)
+VALUE rb_Rational(VALUE, VALUE);
+#define rb_Rational1(x) rb_Rational(x, INT2FIX(1))
+#define rb_Rational2(x,y) rb_Rational(x, y)
+/* complex.c */
+VALUE rb_complex_raw(VALUE, VALUE);
+#define rb_complex_raw1(x) rb_complex_raw(x, INT2FIX(0))
+#define rb_complex_raw2(x,y) rb_complex_raw(x, y)
+VALUE rb_complex_new(VALUE, VALUE);
+#define rb_complex_new1(x) rb_complex_new(x, INT2FIX(0))
+#define rb_complex_new2(x,y) rb_complex_new(x, y)
+VALUE rb_Complex(VALUE, VALUE);
+#define rb_Complex1(x) rb_Complex(x, INT2FIX(0))
+#define rb_Complex2(x,y) rb_Complex(x, y)
 /* class.c */
 VALUE rb_class_boot(VALUE);
 VALUE rb_class_new(VALUE);
Index: include/ruby/ruby.h
===================================================================
--- include/ruby/ruby.h	(revision 15782)
+++ include/ruby/ruby.h	(revision 15783)
@@ -273,6 +273,11 @@
     RUBY_T_SYMBOL = 0x14,
 #define T_SYMBOL RUBY_T_SYMBOL
 
+    RUBY_T_RATIONAL = 0x15,
+#define T_RATIONAL RUBY_T_RATIONAL
+    RUBY_T_COMPLEX = 0x16,
+#define T_COMPLEX RUBY_T_COMPLEX
+
     RUBY_T_VALUES = 0x1a,
 #define T_VALUES RUBY_T_VALUES
     RUBY_T_BLOCK  = 0x1b,
@@ -522,6 +527,18 @@
     struct rb_io_t *fptr;
 };
 
+struct RRational {
+    struct RBasic basic;
+    VALUE num;
+    VALUE den;
+};
+
+struct RComplex {
+    struct RBasic basic;
+    VALUE real;
+    VALUE image;
+};
+
 struct RData {
     struct RBasic basic;
     void (*dmark)(void*);
@@ -622,6 +639,8 @@
 #define RSTRUCT(obj) (R_CAST(RStruct)(obj))
 #define RBIGNUM(obj) (R_CAST(RBignum)(obj))
 #define RFILE(obj)   (R_CAST(RFile)(obj))
+#define RRATIONAL(obj) (R_CAST(RRational)(obj))
+#define RCOMPLEX(obj) (R_CAST(RComplex)(obj))
 #define RVALUES(obj) (R_CAST(RValues)(obj))
 
 #define FL_SINGLETON FL_USER0
@@ -851,6 +870,8 @@
 RUBY_EXTERN VALUE rb_cNumeric;
 RUBY_EXTERN VALUE rb_cProc;
 RUBY_EXTERN VALUE rb_cRange;
+RUBY_EXTERN VALUE rb_cRational;
+RUBY_EXTERN VALUE rb_cComplex;
 RUBY_EXTERN VALUE rb_cRegexp;
 RUBY_EXTERN VALUE rb_cStat;
 RUBY_EXTERN VALUE rb_cString;
Index: configure.in
===================================================================
--- configure.in	(revision 15782)
+++ configure.in	(revision 15783)
@@ -693,7 +693,7 @@
 	      getpgrp setpgrp getpgid setpgid initgroups getgroups setgroups\
 	      getpriority getrlimit setrlimit sysconf group_member\
 	      dlopen sigprocmask sigaction sigsetjmp _setjmp vsnprintf snprintf\
-	      setsid telldir seekdir fchmod cosh sinh tanh log2 round\
+	      setsid telldir seekdir fchmod cosh sinh tanh log2 round signbit\
 	      setuid setgid daemon select_large_fdset setenv unsetenv\
 	      mktime timegm clock_gettime gettimeofday)
 AC_ARG_ENABLE(setreuid,
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 15782)
+++ ChangeLog	(revision 15783)
@@ -1,3 +1,43 @@
+Sun Mar 16 08:51:41 2008  Tadayoshi Funaba  <tadf@d...>
+
+	* include/ruby/intern.h: added some declarations.
+
+	* include/ruby/ruby.h: ditto.
+
+	* common.mk: added some entries.
+
+	* configure.in: added a check for signbit.
+
+	* lib/complex.rb: nearly all of core definitions have been removed.
+
+	* lib/rational.rb: ditto.
+
+	* lib/mathn.rb: some trivial adjustments.
+
+	* complex.c: new.
+
+	* rational.c: ditto.
+
+	* numeric.c (flo_{quo,rdiv}, fix_fdiv): added.
+
+	* numeric.c ({num,int}_{numerator,denominator}): ditto.
+
+	* bignum.c (rb_big_fdiv): ditto.
+
+	* numeric.c (fix_{quo,pow}): now may yield rational number.
+
+	* bignum.c (rb_big_{quo,pow}): ditto.
+
+	* numeric.c (rb_{int,flo}_induced_from): now can accept rational.
+
+	* gc.c (gc_mark_children, obj_free): now detects complex and rational.
+
+	* inits.c (rb_call_inits): now calls Init_{Complex,Rational}.
+
+	* test/ruby/test_complex.rb: new.
+
+	* test/ruby/test_rational.rb: ditto.
+
 Sat Mar 15 17:48:48 2008  Yukihiro Matsumoto  <matz@r...>
 
 	* encoding.c (rb_enc_associate_index): pass unnecessary enc_capable().
Index: lib/rational.rb
===================================================================
--- lib/rational.rb	(revision 15782)
+++ lib/rational.rb	(revision 15783)
@@ -1,469 +1,23 @@
-#
-#   rational.rb -
-#       $Release Version: 0.5 $
-#       $Revision: 1.7 $
-#       by Keiju ISHITSUKA(SHL Japan Inc.)
-#
-# Documentation by Kevin Jackson and Gavin Sinclair.
-# 
-# When you <tt>require 'rational'</tt>, all interactions between numbers
-# potentially return a rational result.  For example:
-#
-#   1.quo(2)              # -> 0.5
-#   require 'rational'
-#   1.quo(2)              # -> Rational(1,2)
-# 
-# See Rational for full documentation.
-#
+class Fixnum
 
-#
-# Creates a Rational number (i.e. a fraction).  +a+ and +b+ should be Integers:
-# 
-#   Rational(1,3)           # -> 1/3
-#
-# Note: trying to construct a Rational with floating point or real values
-# produces errors:
-#
-#   Rational(1.1, 2.3)      # -> NoMethodError
-#
-def Rational(a, b = 1)
-  if a.kind_of?(Rational) && b == 1
-    a
-  else
-    Rational.reduce(a, b)
-  end
-end
+  alias quof fdiv
 
-#
-# Rational implements a rational class for numbers.
-#
-# <em>A rational number is a number that can be expressed as a fraction p/q
-# where p and q are integers and q != 0.  A rational number p/q is said to have
-# numerator p and denominator q.  Numbers that are not rational are called
-# irrational numbers.</em> (http://mathworld.wolfram.com/RationalNumber.html)
-#
-# To create a Rational Number:
-#   Rational(a,b)             # -> a/b
-#   Rational.new!(a,b)        # -> a/b
-#
-# Examples:
-#   Rational(5,6)             # -> 5/6
-#   Rational(5)               # -> 5/1
-# 
-# Rational numbers are reduced to their lowest terms:
-#   Rational(6,10)            # -> 3/5
-#
-# But not if you use the unusual method "new!":
-#   Rational.new!(6,10)       # -> 6/10
-#
-# Division by zero is obviously not allowed:
-#   Rational(3,0)             # -> ZeroDivisionError
-#
-class Rational < Numeric
-  @RCS_ID='-$Id: rational.rb,v 1.7 1999/08/24 12:49:28 keiju Exp keiju $-'
+  alias power! **
+  alias rpower **
 
-  #
-  # Reduces the given numerator and denominator to their lowest terms.  Use
-  # Rational() instead.
-  #
-  def Rational.reduce(num, den = 1)
-    raise ZeroDivisionError, "denominator is zero" if den == 0
+end
 
-    if den < 0
-      num = -num
-      den = -den
-    end
-    gcd = num.gcd(den)
-    num = num.div(gcd)
-    den = den.div(gcd)
-    if den == 1 && defined?(Unify)
-      num
-    else
-      new!(num, den)
-    end
-  end
+class Bignum
 
-  #
-  # Implements the constructor.  This method does not reduce to lowest terms or
-  # check for division by zero.  Therefore #Rational() should be preferred in
-  # normal use.
-  #
-  def Rational.new!(num, den = 1)
-    new(num, den)
-  end
+  alias quof fdiv
 
-  private_class_method :new
+  alias power! **
+  alias rpower **
 
-  #
-  # This method is actually private.
-  #
-  def initialize(num, den)
-    if den < 0
-      num = -num
-      den = -den
-    end
-    if num.kind_of?(Integer) and den.kind_of?(Integer)
-      @numerator = num
-      @denominator = den
-    else
-      @numerator = num.to_i
-      @denominator = den.to_i
-    end
-  end
-
-  #
-  # Returns the addition of this value and +a+.
-  #
-  # Examples:
-  #   r = Rational(3,4)      # -> Rational(3,4)
-  #   r + 1                  # -> Rational(7,4)
-  #   r + 0.5                # -> 1.25
-  #
-  def + (a)
-    if a.kind_of?(Rational)
-      num = @numerator * a.denominator
-      num_a = a.numerator * @denominator
-      Rational(num + num_a, @denominator * a.denominator)
-    elsif a.kind_of?(Integer)
-      self + Rational.new!(a, 1)
-    elsif a.kind_of?(Float)
-      Float(self) + a
-    else
-      x, y = a.coerce(self)
-      x + y
-    end
-  end
-
-  #
-  # Returns the difference of this value and +a+.
-  # subtracted.
-  #
-  # Examples:
-  #   r = Rational(3,4)    # -> Rational(3,4)
-  #   r - 1                # -> Rational(-1,4)
-  #   r - 0.5              # -> 0.25
-  #
-  def - (a)
-    if a.kind_of?(Rational)
-      num = @numerator * a.denominator
-      num_a = a.numerator * @denominator
-      Rational(num - num_a, @denominator*a.denominator)
-    elsif a.kind_of?(Integer)
-      self - Rational.new!(a, 1)
-    elsif a.kind_of?(Float)
-      Float(self) - a
-    else
-      x, y = a.coerce(self)
-      x - y
-    end
-  end
-
-  #
-  # Returns the product of this value and +a+.
-  #
-  # Examples:
-  #   r = Rational(3,4)    # -> Rational(3,4)
-  #   r * 2                # -> Rational(3,2)
-  #   r * 4                # -> Rational(3,1)
-  #   r * 0.5              # -> 0.375
-  #   r * Rational(1,2)    # -> Rational(3,8)
-  #
-  def * (a)
-    if a.kind_of?(Rational)
-      num = @numerator * a.numerator
-      den = @denominator * a.denominator
-      Rational(num, den)
-    elsif a.kind_of?(Integer)
-      self * Rational.new!(a, 1)
-    elsif a.kind_of?(Float)
-      Float(self) * a
-    else
-      x, y = a.coerce(self)
-      x * y
-    end
-  end
-
-  #
-  # Returns the quotient of this value and +a+.
-  #   r = Rational(3,4)    # -> Rational(3,4)
-  #   r / 2                # -> Rational(3,8)
-  #   r / 2.0              # -> 0.375
-  #   r / Rational(1,2)    # -> Rational(3,2)
-  #
-  def / (a)
-    if a.kind_of?(Rational)
-      num = @numerator * a.denominator
-      den = @denominator * a.numerator
-      Rational(num, den)
-    elsif a.kind_of?(Integer)
-      raise ZeroDivisionError, "division by zero" if a == 0
-      self / Rational.new!(a, 1)
-    elsif a.kind_of?(Float)
-      Float(self) / a
-    else
-      x, y = a.coerce(self)
-      x / y
-    end
-  end
-
-  #
-  # Returns this value raised to the given power.
-  #
-  # Examples:
-  #   r = Rational(3,4)    # -> Rational(3,4)
-  #   r ** 2               # -> Rational(9,16)
-  #   r ** 2.0             # -> 0.5625
-  #   r ** Rational(1,2)   # -> 0.866025403784439
-  #
-  def ** (other)
-    if other.kind_of?(Rational)
-      Float(self) ** other
-    elsif other.kind_of?(Integer)
-      if other > 0
-	num = @numerator ** other
-	den = @denominator ** other
-      elsif other < 0
-	num = @denominator ** -other
-	den = @numerator ** -other
-      elsif other == 0
-	num = 1
-	den = 1
-      end
-      Rational.new!(num, den)
-    elsif other.kind_of?(Float)
-      Float(self) ** other
-    else
-      x, y = other.coerce(self)
-      x ** y
-    end
-  end
-
-  def div(other)
-    (self / other).floor
-  end
-
-  #
-  # Returns the remainder when this value is divided by +other+.
-  #
-  # Examples:
-  #   r = Rational(7,4)    # -> Rational(7,4)
-  #   r % Rational(1,2)    # -> Rational(1,4)
-  #   r % 1                # -> Rational(3,4)
-  #   r % Rational(1,7)    # -> Rational(1,28)
-  #   r % 0.26             # -> 0.19
-  #
-  def % (other)
-    value = (self / other).floor
-    return self - other * value
-  end
-
-  #
-  # Returns the quotient _and_ remainder.
-  #
-  # Examples:
-  #   r = Rational(7,4)        # -> Rational(7,4)
-  #   r.divmod Rational(1,2)   # -> [3, Rational(1,4)]
-  #
-  def divmod(other)
-    value = (self / other).floor
-    return value, self - other * value
-  end
-
-  #
-  # Returns the absolute value.
-  #
-  def abs
-    if @numerator > 0
-      self
-    else
-      Rational.new!(-@numerator, @denominator)
-    end
-  end
-
-  #
-  # Returns +true+ iff this value is numerically equal to +other+.
-  #
-  # But beware:
-  #   Rational(1,2) == Rational(4,8)          # -> true
-  #   Rational(1,2) == Rational.new!(4,8)     # -> false
-  #
-  # Don't use Rational.new!
-  #
-  def == (other)
-    if other.kind_of?(Rational)
-      @numerator == other.numerator and @denominator == other.denominator
-    elsif other.kind_of?(Integer)
-      self == Rational.new!(other, 1)
-    elsif other.kind_of?(Float)
-      Float(self) == other
-    else
-      other == self
-    end
-  end
-
-  #
-  # Standard comparison operator.
-  #
-  def <=> (other)
-    if other.kind_of?(Rational)
-      num = @numerator * other.denominator
-      num_a = other.numerator * @denominator
-      v = num - num_a
-      if v > 0
-	return 1
-      elsif v < 0
-	return  -1
-      else
-	return 0
-      end
-    elsif other.kind_of?(Integer)
-      return self <=> Rational.new!(other, 1)
-    elsif other.kind_of?(Float)
-      return Float(self) <=> other
-    elsif defined? other.coerce
-      x, y = other.coerce(self)
-      return x <=> y
-    else
-      return nil
-    end
-  end
-
-  def coerce(other)
-    if other.kind_of?(Float)
-      return other, self.to_f
-    elsif other.kind_of?(Integer)
-      return Rational.new!(other, 1), self
-    else
-      super
-    end
-  end
-
-  #
-  # Converts the rational to an Integer.  Not the _nearest_ integer, the
-  # truncated integer.  Study the following example carefully:
-  #   Rational(+7,4).to_i             # -> 1
-  #   Rational(-7,4).to_i             # -> -2
-  #   (-1.75).to_i                    # -> -1
-  #
-  # In other words:
-  #   Rational(-7,4) == -1.75                 # -> true
-  #   Rational(-7,4).to_i == (-1.75).to_i     # false
-  #
-
-  def floor()
-    @numerator.div(@denominator)
-  end
-
-  def ceil()
-    -((-@numerator).div(@denominator))
-  end
-
-  def truncate()
-    if @numerator < 0
-      return -((-@numerator).div(@denominator))
-    end
-    @numerator.div(@denominator)
-  end
-
-  alias_method :to_i, :truncate
-
-  def round()
-    if @numerator < 0
-      num = -@numerator
-      num = num * 2 + @denominator
-      den = @denominator * 2
-      -(num.div(den))
-    else
-      num = @numerator * 2 + @denominator
-      den = @denominator * 2
-      num.div(den)
-    end
-  end
-
-  #
-  # Converts the rational to a Float.
-  #
-  def to_f
-    @numerator.quof(@denominator)
-  end
-
-  #
-  # Returns a string representation of the rational number.
-  #
-  # Example:
-  #   Rational(3,4).to_s          #  "3/4"
-  #   Rational(8).to_s            #  "8"
-  #
-  def to_s
-    if @denominator == 1
-      @numerator.to_s
-    else
-      @numerator.to_s+"/"+@d..._s
-    end
-  end
-
-  #
-  # Returns +self+.
-  #
-  def to_r
-    self
-  end
-
-  #
-  # Returns a reconstructable string representation:
-  #
-  #   Rational(5,8).inspect     # -> "Rational(5, 8)"
-  #
-  def inspect
-    sprintf("Rational(%s, %s)", @numerator.inspect, @denominator.inspect)
-  end
-
-  #
-  # Returns a hash code for the object.
-  #
-  def hash
-    @numerator.hash ^ @denominator.hash
-  end
-
-  attr :numerator
-  attr :denominator
-
-  private :initialize
 end
 
 class Integer
-  #
-  # In an integer, the value _is_ the numerator of its rational equivalent.
-  # Therefore, this method returns +self+.
-  #
-  def numerator
-    self
-  end
 
-  #
-  # In an integer, the denominator is 1.  Therefore, this method returns 1.
-  #
-  def denominator
-    1
-  end
-
-  #
-  # Returns a Rational representation of this integer.
-  #
-  def to_r
-    Rational(self, 1)
-  end
-
-  #
-  # Returns the <em>greatest common denominator</em> of the two numbers (+self+
-  # and +n+).
-  #
-  # Examples:
-  #   72.gcd 168           # -> 24
-  #   19.gcd 36            # -> 1
-  #
-  # The result is positive, no matter the sign of the arguments.
-  #
   def gcd(other)
     min = self.abs
     max = other.abs
@@ -475,10 +29,6 @@
     max
   end
 
-  # Examples:
-  #   6.lcm 7        # -> 42
-  #   6.lcm 9        # -> 18
-  #
   def lcm(other)
     if self.zero? or other.zero?
       0
@@ -486,15 +36,7 @@
       (self.div(self.gcd(other)) * other).abs
     end
   end
-  
-  #
-  # Returns the GCD _and_ the LCM (see #gcd and #lcm) of the two arguments
-  # (+self+ and +other+).  This is more efficient than calculating them
-  # separately.
-  #
-  # Example:
-  #   6.gcdlcm 9     # -> [3, 18]
-  #
+
   def gcdlcm(other)
     gcd = self.gcd(other)
     if self.zero? or other.zero?
@@ -503,55 +45,5 @@
       [gcd, (self.div(gcd) * other).abs]
     end
   end
-end
 
-class Fixnum
-  alias quof quo
-  remove_method :quo
-
-  # If Rational is defined, returns a Rational number instead of a Float.
-  def quo(other)
-    Rational.new!(self, 1) / other
-  end
-  alias rdiv quo
-
-  # Returns a Rational number if the result is in fact rational (i.e. +other+ < 0).
-  def rpower (other)
-    if other >= 0
-      self.power!(other)
-    else
-      Rational.new!(self, 1)**other
-    end
-  end
 end
-
-class Bignum
-  alias quof quo
-  remove_method :quo
-
-  # If Rational is defined, returns a Rational number instead of a Float.
-  def quo(other)
-    Rational.new!(self, 1) / other
-  end
-  alias rdiv quo
-
-  # Returns a Rational number if the result is in fact rational (i.e. +other+ < 0).
-  def rpower (other)
-    if other >= 0
-      self.power!(other)
-    else
-      Rational.new!(self, 1)**other
-    end
-  end
-end
-
-unless defined? 1.power!
-  class Fixnum
-    alias power! **
-    alias ** rpower
-  end
-  class Bignum
-    alias power! **
-    alias ** rpower
-  end
-end
Index: lib/mathn.rb
===================================================================
--- lib/mathn.rb	(revision 15782)
+++ lib/mathn.rb	(revision 15783)
@@ -127,7 +127,7 @@
     if other.kind_of?(Rational)
       other2 = other
       if self < 0
-	return Complex.new!(self, 0) ** other
+	return Complex.__send__(:new!, self, 0) ** other
       elsif other == 0
 	return Rational(1,1)
       elsif self == 0
@@ -175,7 +175,7 @@
 	num = 1
 	den = 1
       end
-      Rational.new!(num, den)
+      Rational(num, den)
     elsif other.kind_of?(Float)
       Float(self) ** other
     else
@@ -187,7 +187,7 @@
   def power2(other)
     if other.kind_of?(Rational)
       if self < 0
-	return Complex(self, 0) ** other
+	return Complex.__send__(:new!, self, 0) ** other
       elsif other == 0
 	return Rational(1,1)
       elsif self == 0
@@ -219,7 +219,7 @@
 	num = 1
 	den = 1
       end
-      Rational.new!(num, den)
+      Rational(num, den)
     elsif other.kind_of?(Float)
       Float(self) ** other
     else
@@ -306,4 +306,3 @@
 class Complex
   Unify = true
 end
-
Index: lib/complex.rb
===================================================================
--- lib/complex.rb	(revision 15782)
+++ lib/complex.rb	(revision 15783)
@@ -1,473 +1,90 @@
-#
-#   complex.rb - 
-#   	$Release Version: 0.5 $
-#   	$Revision: 1.3 $
-#   	by Keiju ISHITSUKA(SHL Japan Inc.)
-#
-# ----
-#
-# complex.rb implements the Complex class for complex numbers.  Additionally,
-# some methods in other Numeric classes are redefined or added to allow greater
-# interoperability with Complex numbers.
-#
-# Complex numbers can be created in the following manner:
-# - <tt>Complex(a, b)</tt>
-# - <tt>Complex.polar(radius, theta)</tt>
-#   
-# Additionally, note the following:
-# - <tt>Complex::I</tt> (the mathematical constant <i>i</i>)
-# - <tt>Numeric#im</tt> (e.g. <tt>5.im -> 0+5i</tt>)
-#
-# The following +Math+ module methods are redefined to handle Complex arguments.
-# They will work as normal with non-Complex arguments.
-#    sqrt exp cos sin tan log log10
-#    cosh sinh tanh acos asin atan atan2 acosh asinh atanh
-#
+class Integer
 
-
-#
-# Numeric is a built-in class on which Fixnum, Bignum, etc., are based.  Here
-# some methods are added so that all number types can be treated to some extent
-# as Complex numbers.
-#
-class Numeric
-  #
-  # Returns a Complex number <tt>(0,<i>self</i>)</tt>.
-  #
-  def im
-    Complex(0, self)
-  end
-  
-  #
-  # The real part of a complex number, i.e. <i>self</i>.
-  #
-  def real
-    self
-  end
-  
-  #
-  # The imaginary part of a complex number, i.e. 0.
-  #
-  def image
-    0
-  end
-  alias imag image
-  
-  #
-  # See Complex#arg.
-  #
-  def arg
-    if self >= 0
-      return 0
-    else
-      return Math::PI
+  def gcd(other)
+    min = self.abs
+    max = other.abs
+    while min > 0
+      tmp = min
+      min = max % min
+      max = tmp
     end
+    max
   end
-  alias angle arg
-  
-  #
-  # See Complex#polar.
-  #
-  def polar
-    return abs, arg
-  end
-  
-  #
-  # See Complex#conjugate (short answer: returns <i>self</i>).
-  #
-  def conjugate
-    self
-  end
-  alias conj conjugate
-end
 
-
-#
-# Creates a Complex number.  +a+ and +b+ should be Numeric.  The result will be
-# <tt>a+bi</tt>.
-#
-def Complex(a, b = 0)
-  if b == 0 and (a.kind_of?(Complex) or defined? Complex::Unify)
-    a
-  elsif a.scalar? and b.scalar?
-    # Don't delete for -0.0
-    Complex.new(a, b)
-  else
-    Complex.new( a.real-b.imag, a.imag+b.real )
-  end
-end
-
-#
-# The complex number class.  See complex.rb for an overview.
-#
-class Complex < Numeric
-  @RCS_ID='-$Id: complex.rb,v 1.3 1998/07/08 10:05:28 keiju Exp keiju $-'
-
-  undef step
-  undef <, <=, <=>, >, >=
-  undef between?
-  undef div, divmod, modulo
-  undef floor, truncate, ceil, round
-
-  def scalar?
-    false
-  end
-
-  def Complex.generic?(other) # :nodoc:
-    other.kind_of?(Integer) or
-    other.kind_of?(Float) or
-    (defined?(Rational) and other.kind_of?(Rational))
-  end
-
-  #
-  # Creates a +Complex+ number in terms of +r+ (radius) and +theta+ (angle).
-  #
-  def Complex.polar(r, theta)
-    Complex(r*Math.cos(theta), r*Math.sin(theta))
-  end
-
-  #
-  # Creates a +Complex+ number <tt>a</tt>+<tt>b</tt><i>i</i>.
-  #
-  def Complex.new!(a, b=0)
-    new(a,b)
-  end
-
-  def initialize(a, b)
-    raise TypeError, "non numeric 1st arg `#{a.inspect}'" if !a.kind_of? Numeric
-    raise TypeError, "`#{a.inspect}' for 1st arg" if a.kind_of? Complex
-    raise TypeError, "non numeric 2nd arg `#{b.inspect}'" if !b.kind_of? Numeric
-    raise TypeError, "`#{b.inspect}' for 2nd arg" if b.kind_of? Complex
-    @real = a
-    @image = b
-  end
-
-  #
-  # Addition with real or complex number.
-  #
-  def + (other)
-    if other.kind_of?(Complex)
-      re = @real + other.real
-      im = @image + other.image
-      Complex(re, im)
-    elsif Complex.generic?(other)
-      Complex(@real + other, @image)
+  def lcm(other)
+    if self.zero? or other.zero?
+      0
     else
-      x , y = other.coerce(self)
-      x + y
+      (self.div(self.gcd(other)) * other).abs
     end
   end
-  
-  #
-  # Subtraction with real or complex number.
-  #
-  def - (other)
-    if other.kind_of?(Complex)
-      re = @real - other.real
-      im = @image - other.image
-      Complex(re, im)
-    elsif Complex.generic?(other)
-      Complex(@real - other, @image)
-    else
-      x , y = other.coerce(self)
-      x - y
-    end
-  end
-  
-  #
-  # Multiplication with real or complex number.
-  #
-  def * (other)
-    if other.kind_of?(Complex)
-      re = @real*other.real - @image*other.image
-      im = @real*other.image + @image*other.real
-      Complex(re, im)
-    elsif Complex.generic?(other)
-      Complex(@real * other, @image * other)
-    else
-      x , y = other.coerce(self)
-      x * y
-    end
-  end
-  
-  #
-  # Division by real or complex number.
-  #
-  def / (other)
-    if other.kind_of?(Complex)
-      self*other.conjugate/other.abs2
-    elsif Complex.generic?(other)
-      Complex(@real/other, @image/other)
-    else
-      x, y = other.coerce(self)
-      x/y
-    end
-  end
 
-  def quo(other)
-    Complex(@real.quo(1), @image.quo(1)) / other
-  end
-  
-  #
-  # Raise this complex number to the given (real or complex) power.
-  #
-  def ** (other)
-    if other == 0
-      return Complex(1)
-    end
-    if other.kind_of?(Complex)
-      r, theta = polar
-      ore = other.real
-      oim = other.image
-      nr = Math.exp!(ore*Math.log!(r) - oim * theta)
-      ntheta = theta*ore + oim*Math.log!(r)
-      Complex.polar(nr, ntheta)
-    elsif other.kind_of?(Integer)
-      if other > 0
-	x = self
-	z = x
-	n = other - 1
-	while n != 0
-	  while (div, mod = n.divmod(2)
-		 mod == 0)
-	    x = Complex(x.real*x.real - x.image*x.image, 2*x.real*x.image)
-	    n = div
-	  end
-	  z *= x
-	  n -= 1
-	end
-	z
-      else
-	if defined? Rational
-	  (Rational(1) / self) ** -other
-	else
-	  self ** Float(other)
-	end
-      end
-    elsif Complex.generic?(other)
-      r, theta = polar
-      Complex.polar(r**other, theta*other)
+  def gcdlcm(other)
+    gcd = self.gcd(other)
+    if self.zero? or other.zero?
+      [gcd, 0]
     else
-      x, y = other.coerce(self)
-      x**y
+      [gcd, (self.div(gcd) * other).abs]
     end
   end
-  
-  #
-  # Remainder after division by a real or complex number.
-  #
 
-=begin
-  def % (other)
-    if other.kind_of?(Complex)
-      Complex(@real % other.real, @image % other.image)
-    elsif Complex.generic?(other)
-      Complex(@real % other, @image % other)
-    else
-      x , y = other.coerce(self)
-      x % y
-    end
-  end
-=end
-
-#--
-#    def divmod(other)
-#      if other.kind_of?(Complex)
-#        rdiv, rmod = @real.divmod(other.real)
-#        idiv, imod = @image.divmod(other.image)
-#        return Complex(rdiv, idiv), Complex(rmod, rmod)
-#      elsif Complex.generic?(other)
-#        Complex(@real.divmod(other), @image.divmod(other))
-#      else
-#        x , y = other.coerce(self)
-#        x.divmod(y)
-#      end
-#    end
-#++
-  
-  #
-  # Absolute value (aka modulus): distance from the zero point on the complex
-  # plane.
-  #
-  def abs
-    Math.hypot(@real, @image)
-  end
-  
-  #
-  # Square of the absolute value.
-  #
-  def abs2
-    @real*@real + @image*@image
-  end
-  
-  #
-  # Argument (angle from (1,0) on the complex plane).
-  #
-  def arg
-    Math.atan2!(@image, @real)
-  end
-  alias angle arg
-  
-  #
-  # Returns the absolute value _and_ the argument.
-  #
-  def polar
-    return abs, arg
-  end
-  
-  #
-  # Complex conjugate (<tt>z + z.conjugate = 2 * z.real</tt>).
-  #
-  def conjugate
-    Complex(@real, -@image)
-  end
-  alias conj conjugate
-
-  #
-  # Test for numerical equality (<tt>a == a + 0<i>i</i></tt>).
-  #
-  def == (other)
-    if other.kind_of?(Complex)
-      @real == other.real and @image == other.image
-    elsif Complex.generic?(other)
-      @real == other and @image == 0
-    else
-      other == self
-    end
-  end
-
-  #
-  # Attempts to coerce +other+ to a Complex number.
-  #
-  def coerce(other)
-    if Complex.generic?(other)
-      return Complex.new!(other), self
-    else
-      super
-    end
-  end
-
-  #
-  # FIXME
-  #
-  def denominator
-    @real.denominator.lcm(@image.denominator)
-  end
-  
-  #
-  # FIXME
-  #
-  def numerator
-    cd = denominator
-    Complex(@real.numerator*(cd/@r...),
-	    @image.numerator*(cd/@i...))
-  end
-  
-  #
-  # Standard string representation of the complex number.
-  #
-  def to_s
-    if @real != 0
-      if defined?(Rational) and @image.kind_of?(Rational) and @image.denominator != 1
-	if @image >= 0
-	  @real.to_s+"+("+@i..._s+")i"
-	else
-	  @real.to_s+"-("+(-@image).to_s+")i"
-	end
-      else
-	if @image >= 0
-	  @real.to_s+"+"+@i..._s+"i"
-	else
-	  @real.to_s+"-"+(-@image).to_s+"i"
-	end
-      end
-    else
-      if defined?(Rational) and @image.kind_of?(Rational) and @image.denominator != 1
-	"("+@i..._s+")i"
-      else
-	@image.to_s+"i"
-      end
-    end
-  end
-  
-  #
-  # Returns a hash code for the complex number.
-  #
-  def hash
-    @real.hash ^ @image.hash
-  end
-  
-  #
-  # Returns "<tt>Complex(<i>real</i>, <i>image</i>)</tt>".
-  #
-  def inspect
-    sprintf("Complex(%s, %s)", @real.inspect, @image.inspect)
-  end
-
-  
-  #
-  # +I+ is the imaginary number.  It exists at point (0,1) on the complex plane.
-  #
-  I = Complex(0,1)
-  
-  # The real part of a complex number.
-  attr_reader :real
-
-  # The imaginary part of a complex number.
-  attr_reader :image
-  alias imag image
-  
 end
 
-class Integer
-
-  unless defined?(1.numerator)
-    def numerator() self end
-    def denominator() 1 end
-
-    def gcd(other)
-      min = self.abs
-      max = other.abs
-      while min > 0
-        tmp = min
-        min = max % min
-        max = tmp
-      end
-      max
-    end
-
-    def lcm(other)
-      if self.zero? or other.zero?
-        0
-      else
-        (self.div(self.gcd(other)) * other).abs
-      end
-    end
-
-  end
-
-end
-
 module Math
-  alias sqrt! sqrt
+
   alias exp! exp
   alias log! log
   alias log10! log10
-  alias cos! cos
+  alias sqrt! sqrt
+
   alias sin! sin
+  alias cos! cos
   alias tan! tan
-  alias cosh! cosh
+
   alias sinh! sinh
+  alias cosh! cosh
   alias tanh! tanh
-  alias acos! acos
+
   alias asin! asin
+  alias acos! acos
   alias atan! atan
   alias atan2! atan2
-  alias acosh! acosh
+
   alias asinh! asinh
-  alias atanh! atanh  
+  alias acosh! acosh
+  alias atanh! atanh
 
-  # Redefined to handle a Complex argument.
+  def exp(z)
+    if Complex.generic?(z)
+      exp!(z)
+    else
+      Complex(exp!(z.real) * cos!(z.image),
+	      exp!(z.real) * sin!(z.image))
+    end
+  end
+
+  def log(*args)
+    z, b = args
+    if Complex.generic?(z) and z >= 0 and (b.nil? or b >= 0)
+      log!(*args)
+    else
+      r, theta = z.polar
+      a = Complex(log!(r.abs), theta)
+      if b
+	a /= log(b)
+      end
+      a
+    end
+  end
+
+  def log10(z)
+    if Complex.generic?(z)
+      log10!(z)
+    else
+      log(z) / log!(10)
+    end
+  end
+
   def sqrt(z)
     if Complex.generic?(z)
       if z >= 0
@@ -481,41 +98,29 @@
       else
 	r = z.abs
 	x = z.real
-	Complex( sqrt!((r+x)/2), sqrt!((r-x)/2) )
+	Complex(sqrt!((r + x) / 2), sqrt!((r - x) / 2))
       end
     end
   end
-  
-  # Redefined to handle a Complex argument.
-  def exp(z)
+
+  def sin(z)
     if Complex.generic?(z)
-      exp!(z)
+      sin!(z)
     else
-      Complex(exp!(z.real) * cos!(z.image), exp!(z.real) * sin!(z.image))
+      Complex(sin!(z.real) * cosh!(z.image),
+	      cos!(z.real) * sinh!(z.image))
     end
   end
-  
-  # Redefined to handle a Complex argument.
+
   def cos(z)
     if Complex.generic?(z)
       cos!(z)
     else
-      Complex(cos!(z.real)*cosh!(z.image),
-	      -sin!(z.real)*sinh!(z.image))
+      Complex(cos!(z.real) * cosh!(z.image),
+	      -sin!(z.real) * sinh!(z.image))
     end
   end
-    
-  # Redefined to handle a Complex argument.
-  def sin(z)
-    if Complex.generic?(z)
-      sin!(z)
-    else
-      Complex(sin!(z.real)*cosh!(z.image),
-	      cos!(z.real)*sinh!(z.image))
-    end
-  end
-  
-  # Redefined to handle a Complex argument.
+
   def tan(z)
     if Complex.generic?(z)
       tan!(z)
@@ -528,7 +133,8 @@
     if Complex.generic?(z)
       sinh!(z)
     else
-      Complex( sinh!(z.real)*cos!(z.image), cosh!(z.real)*sin!(z.image) )
+      Complex(sinh!(z.real) * cos!(z.image),
+	      cosh!(z.real) * sin!(z.image))
     end
   end
 
@@ -536,7 +142,8 @@
     if Complex.generic?(z)
       cosh!(z)
     else
-      Complex( cosh!(z.real)*cos!(z.image), sinh!(z.real)*sin!(z.image) )
+      Complex(cosh!(z.real) * cos!(z.image),
+	      sinh!(z.real) * sin!(z.image))
     end
   end
 
@@ -544,50 +151,31 @@
     if Complex.generic?(z)
       tanh!(z)
     else
-      sinh(z)/cosh(z)
+      sinh(z) / cosh(z)
     end
   end
-  
-  # Redefined to handle a Complex argument.
-  def log(z)
-    if Complex.generic?(z) and z >= 0
-      log!(z)
+
+  def asin(z)
+    if Complex.generic?(z) and z >= -1 and z <= 1
+      asin!(z)
     else
-      r, theta = z.polar
-      Complex(log!(r.abs), theta)
+      -1.0.im * log(1.0.im * z + sqrt(1.0 - z * z))
     end
   end
-  
-  # Redefined to handle a Complex argument.
-  def log10(z)
-    if Complex.generic?(z)
-      log10!(z)
-    else
-      log(z)/log!(10)
-    end
-  end
 
   def acos(z)
     if Complex.generic?(z) and z >= -1 and z <= 1
       acos!(z)
     else
-      -1.0.im * log( z + 1.0.im * sqrt(1.0-z*z) )
+      -1.0.im * log(z + 1.0.im * sqrt(1.0 - z * z))
     end
   end
 
-  def asin(z)
-    if Complex.generic?(z) and z >= -1 and z <= 1
-      asin!(z)
-    else
-      -1.0.im * log( 1.0.im * z + sqrt(1.0-z*z) )
-    end
-  end
-
   def atan(z)
     if Complex.generic?(z)
       atan!(z)
     else
-      1.0.im * log( (1.0.im+z) / (1.0.im-z) ) / 2.0
+      1.0.im * log((1.0.im + z) / (1.0.im - z)) / 2.0
     end
   end
 
@@ -595,7 +183,7 @@
     if Complex.generic?(y) and Complex.generic?(x)
       atan2!(y,x)
     else
-      -1.0.im * log( (x+1.0.im*y) / sqrt(x*x+y*y) )
+      -1.0.im * log((x + 1.0.im * y) / sqrt(x * x + y * y))
     end
   end
 
@@ -603,7 +191,7 @@
     if Complex.generic?(z) and z >= 1
       acosh!(z)
     else
-      log( z + sqrt(z*z-1.0) )
+      log(z + sqrt(z * z - 1.0))
     end
   end
 
@@ -611,7 +199,7 @@
     if Complex.generic?(z)
       asinh!(z)
     else
-      log( z + sqrt(1.0+z*z) )
+      log(z + sqrt(1.0 + z * z))
     end
   end
 
@@ -619,49 +207,47 @@
     if Complex.generic?(z) and z >= -1 and z <= 1
       atanh!(z)
     else
-      log( (1.0+z) / (1.0-z) ) / 2.0
+      log((1.0 + z) / (1.0 - z)) / 2.0
     end
   end
 
-  module_function :sqrt!
-  module_function :sqrt
   module_function :exp!
   module_function :exp
   module_function :log!
   module_function :log
   module_function :log10!
   module_function :log10
-  module_function :cosh!
-  module_function :cosh
-  module_function :cos!
-  module_function :cos
-  module_function :sinh!
-  module_function :sinh
+  module_function :sqrt!
+  module_function :sqrt
+
   module_function :sin!
   module_function :sin
+  module_function :cos!
+  module_function :cos
   module_function :tan!
   module_function :tan
+
+  module_function :sinh!
+  module_function :sinh
+  module_function :cosh!
+  module_function :cosh
   module_function :tanh!
   module_function :tanh
-  module_function :acos!
-  module_function :acos
+
   module_function :asin!
   module_function :asin
+  module_function :acos!
+  module_function :acos
   module_function :atan!
   module_function :atan
   module_function :atan2!
   module_function :atan2
-  module_function :acosh!
-  module_function :acosh
+
   module_function :asinh!
   module_function :asinh
+  module_function :acosh!
+  module_function :acosh
   module_function :atanh!
   module_function :atanh
-  
-end
 
-# Documentation comments:
-#  - source: original (researched from pickaxe)
-#  - a couple of fixme's
-#  - RDoc output for Bignum etc. is a bit short, with nothing but an
-#    (undocumented) alias.  No big deal.
+end
Index: common.mk
===================================================================
--- common.mk	(revision 15782)
+++ common.mk	(revision 15783)
@@ -23,6 +23,7 @@
 		bignum.$(OBJEXT) \
 		class.$(OBJEXT) \
 		compar.$(OBJEXT) \
+		complex.$(OBJEXT) \
 		dir.$(OBJEXT) \
 		enum.$(OBJEXT) \
 		enumerator.$(OBJEXT) \
@@ -45,6 +46,7 @@
 		prec.$(OBJEXT) \
 		random.$(OBJEXT) \
 		range.$(OBJEXT) \
+		rational.$(OBJEXT) \
 		re.$(OBJEXT) \
 		regcomp.$(OBJEXT) \
 		regenc.$(OBJEXT) \
@@ -424,6 +426,9 @@
 compar.$(OBJEXT): {$(VPATH)}compar.c {$(VPATH)}ruby.h {$(VPATH)}config.h \
   {$(VPATH)}defines.h {$(VPATH)}missing.h {$(VPATH)}intern.h \
   {$(VPATH)}st.h
+complex.$(OBJEXT): {$(VPATH)}complex.c {$(VPATH)}ruby.h {$(VPATH)}config.h \
+  {$(VPATH)}defines.h {$(VPATH)}missing.h {$(VPATH)}intern.h \
+  {$(VPATH)}st.h
 dir.$(OBJEXT): {$(VPATH)}dir.c {$(VPATH)}ruby.h {$(VPATH)}config.h \
   {$(VPATH)}defines.h {$(VPATH)}missing.h {$(VPATH)}intern.h \
   {$(VPATH)}st.h {$(VPATH)}util.h
@@ -530,6 +535,9 @@
 range.$(OBJEXT): {$(VPATH)}range.c {$(VPATH)}ruby.h {$(VPATH)}config.h \
   {$(VPATH)}defines.h {$(VPATH)}missing.h {$(VPATH)}intern.h \
   {$(VPATH)}st.h
+rational.$(OBJEXT): {$(VPATH)}rational.c {$(VPATH)}ruby.h {$(VPATH)}config.h \
+  {$(VPATH)}defines.h {$(VPATH)}missing.h {$(VPATH)}intern.h \
+  {$(VPATH)}st.h
 re.$(OBJEXT): {$(VPATH)}re.c {$(VPATH)}ruby.h {$(VPATH)}config.h \
   {$(VPATH)}defines.h {$(VPATH)}missing.h {$(VPATH)}intern.h \
   {$(VPATH)}st.h {$(VPATH)}re.h {$(VPATH)}regex.h {$(VPATH)}oniguruma.h \
Index: gc.c
===================================================================
--- gc.c	(revision 15782)
+++ gc.c	(revision 15783)
@@ -127,6 +127,8 @@
 	struct RFile   file;
 	struct RNode   node;
 	struct RMatch  match;
+	struct RRational rational;
+	struct RComplex complex;
     } as;
 #ifdef GC_DEBUG
     char *file;
@@ -1128,6 +1130,16 @@
 	}
 	break;
 
+      case T_RATIONAL:
+	gc_mark(obj->as.rational.num, lev);
+	gc_mark(obj->as.rational.den, lev);
+	break;
+
+      case T_COMPLEX:
+	gc_mark(obj->as.complex.real, lev);
+	gc_mark(obj->as.complex.image, lev);
+	break;
+
       case T_STRUCT:
 	{
 	    long len = RSTRUCT_LEN(obj);
@@ -1369,6 +1381,9 @@
 	    rb_io_fptr_finalize(RANY(obj)->as.file.fptr);
 	}
 	break;
+      case T_RATIONAL:
+      case T_COMPLEX:
+	break;
       case T_ICLASS:
 	/* iClass shares table with the module */
 	break;
Index: numeric.c
===================================================================
--- numeric.c	(revision 15782)
+++ numeric.c	(revision 15783)
@@ -646,7 +646,18 @@
     }
 }
 
+static VALUE
+flo_quo(VALUE x, VALUE y)
+{
+    return rb_funcall(x, '/', 1, y);
+}
 
+static VALUE
+flo_rdiv(VALUE x, VALUE y)
+{
+    return rb_funcall(rb_Rational1(x), '/', 1, y);
+}
+
 static void
 flodivmod(double x, double y, double *divp, double *modp)
 {
@@ -1699,7 +1710,18 @@
 
 #endif  /* HAVE_LONG_LONG */
 
+static VALUE
+num_numerator(VALUE num)
+{
+    return rb_funcall(rb_Rational1(num), rb_intern("numerator"), 0);
+}
 
+static VALUE
+num_denominator(VALUE num)
+{
+    return rb_funcall(rb_Rational1(num), rb_intern("denominator"), 0);
+}
+
 /*
  * Document-class: Integer
  *
@@ -1880,6 +1902,18 @@
     return str;
 }
 
+static VALUE
+int_numerator(VALUE num)
+{
+    return num;
+}
+
+static VALUE
+int_denominator(VALUE num)
+{
+    return INT2FIX(1);
+}
+
 /********************************************************************
  *
  * Document-class: Fixnum
@@ -1928,6 +1962,7 @@
       case T_BIGNUM:
 	return x;
       case T_FLOAT:
+      case T_RATIONAL:
 	return rb_funcall(x, id_to_i, 0);
       default:
 	rb_raise(rb_eTypeError, "failed to convert %s into Integer",
@@ -1948,6 +1983,7 @@
     switch (TYPE(x)) {
       case T_FIXNUM:
       case T_BIGNUM:
+      case T_RATIONAL:
 	return rb_funcall(x, rb_intern("to_f"), 0);
       case T_FLOAT:
 	return x;
@@ -2199,6 +2235,12 @@
 static VALUE
 fix_quo(VALUE x, VALUE y)
 {
+    return rb_funcall(rb_rational_raw1(x), '/', 1, y);
+}
+
+static VALUE
+fix_fdiv(VALUE x, VALUE y)
+{
     if (FIXNUM_P(y)) {
 	return DOUBLE2NUM((double)FIX2LONG(x) / (double)FIX2LONG(y));
     }
@@ -2208,7 +2250,7 @@
       case T_FLOAT:
 	return DOUBLE2NUM((double)FIX2LONG(x) / RFLOAT_VALUE(y));
       default:
-	return rb_num_coerce_bin(x, y, rb_intern("quo"));
+	return rb_num_coerce_bin(x, y, rb_intern("fdiv"));
     }
 }
 
@@ -2392,6 +2434,9 @@
     if (FIXNUM_P(y)) {
 	long b = FIX2LONG(y);
 
+	if (b < 0)
+	  return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y);
+
 	if (b == 0) return INT2FIX(1);
 	if (b == 1) return x;
 	if (a == 0) {
@@ -2405,13 +2450,14 @@
 	    else 
 		return INT2FIX(-1);
 	}
-	if (b > 0) {
-	    return int_pow(a, b);
-	}
-	return DOUBLE2NUM(pow((double)a, (double)b));
+	return int_pow(a, b);
     }
     switch (TYPE(y)) {
       case T_BIGNUM:
+
+	if (rb_funcall(y, '<', 1, INT2FIX(0)))
+	  return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y);
+
 	if (a == 0) return INT2FIX(0);
 	if (a == 1) return INT2FIX(1);
 	if (a == -1) {
@@ -3117,6 +3163,7 @@
     rb_define_method(rb_cNumeric, "<=>", num_cmp, 1);
     rb_define_method(rb_cNumeric, "eql?", num_eql, 1);
     rb_define_method(rb_cNumeric, "quo", num_quo, 1);
+    rb_define_method(rb_cNumeric, "rdiv", num_quo, 1);
     rb_define_method(rb_cNumeric, "fdiv", num_quo, 1);
     rb_define_method(rb_cNumeric, "div", num_div, 1);
     rb_define_method(rb_cNumeric, "divmod", num_divmod, 1);
@@ -3136,6 +3183,9 @@
     rb_define_method(rb_cNumeric, "truncate", num_truncate, 0);
     rb_define_method(rb_cNumeric, "step", num_step, -1);
 
+    rb_define_method(rb_cNumeric, "numerator", num_numerator, 0);
+    rb_define_method(rb_cNumeric, "denominator", num_denominator, 0);
+
     rb_cInteger = rb_define_class("Integer", rb_cNumeric);
     rb_undef_alloc_func(rb_cInteger);
     rb_undef_method(CLASS_OF(rb_cInteger), "new");
@@ -3163,6 +3213,9 @@
     rb_define_singleton_method(rb_cFixnum, "induced_from", rb_fix_induced_from, 1);
     rb_define_singleton_method(rb_cInteger, "induced_from", rb_int_induced_from, 1);
 
+    rb_define_method(rb_cInteger, "numerator", int_numerator, 0);
+    rb_define_method(rb_cInteger, "denominator", int_denominator, 0);
+
     rb_define_method(rb_cFixnum, "to_s", fix_to_s, -1);
 
     rb_define_method(rb_cFixnum, "id2name", fix_id2name, 0);
@@ -3178,7 +3231,8 @@
     rb_define_method(rb_cFixnum, "modulo", fix_mod, 1);
     rb_define_method(rb_cFixnum, "divmod", fix_divmod, 1);
     rb_define_method(rb_cFixnum, "quo", fix_quo, 1);
-    rb_define_method(rb_cFixnum, "fdiv", fix_quo, 1);
+    rb_define_method(rb_cFixnum, "rdiv", fix_quo, 1);
+    rb_define_method(rb_cFixnum, "fdiv", fix_fdiv, 1);
     rb_define_method(rb_cFixnum, "**", fix_pow, 1);
 
     rb_define_method(rb_cFixnum, "abs", fix_abs, 0);
@@ -3233,6 +3287,9 @@
     rb_define_method(rb_cFloat, "-", flo_minus, 1);
     rb_define_method(rb_cFloat, "*", flo_mul, 1);
     rb_define_method(rb_cFloat, "/", flo_div, 1);
+    rb_define_method(rb_cFloat, "quo", flo_quo, 1);
+    rb_define_method(rb_cFloat, "rdiv", flo_rdiv, 1);
+    rb_define_method(rb_cFloat, "fdiv", flo_quo, 1);
     rb_define_method(rb_cFloat, "%", flo_mod, 1);
     rb_define_method(rb_cFloat, "modulo", flo_mod, 1);
     rb_define_method(rb_cFloat, "divmod", flo_divmod, 1);
Index: inits.c
===================================================================
--- inits.c	(revision 15782)
+++ inits.c	(revision 15783)
@@ -15,6 +15,7 @@
 void Init_Bignum(void);
 void Init_Binding(void);
 void Init_Comparable(void);
+void Init_Complex(void);
 void Init_transcode(void);
 void Init_Dir(void);
 void Init_Enumerable(void);
@@ -39,6 +40,7 @@
 void Init_process(void);
 void Init_Random(void);
 void Init_Range(void);
+void Init_Rational(void);
 void Init_Regexp(void);
 void Init_signal(void);
 void Init_String(void);
@@ -96,5 +98,7 @@
     Init_ISeq();
     Init_Thread();
     Init_Cont();
+    Init_Rational();
+    Init_Complex();
     Init_version();
 }
Index: bignum.c
===================================================================
--- bignum.c	(revision 15782)
+++ bignum.c	(revision 15783)
@@ -1902,6 +1902,12 @@
 static VALUE
 rb_big_quo(VALUE x, VALUE y)
 {
+    return rb_funcall(rb_rational_raw1(x), '/', 1, y);
+}
+
+static VALUE
+rb_big_fdiv(VALUE x, VALUE y)
+{
     double dx = big2dbl(x);
     double dy;
 
@@ -1947,7 +1953,7 @@
 	break;
 
       default:
-	return rb_num_coerce_bin(x, y, rb_intern("quo"));
+	return rb_num_coerce_bin(x, y, rb_intern("fdiv"));
     }
     return DOUBLE2NUM(dx / dy);
 }
@@ -2025,13 +2031,19 @@
 	break;
 
       case T_BIGNUM:
+	if (rb_funcall(y, '<', 1, INT2FIX(0)))
+	  return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y);
+
 	rb_warn("in a**b, b may be too big");
 	d = rb_big2dbl(y);
 	break;
 
       case T_FIXNUM:
 	yy = FIX2LONG(y);
-	if (yy > 0) {
+
+	if (yy < 0)
+	  return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y);
+	else {
 	    VALUE z = 0;
 	    SIGNED_VALUE mask;
 	    const long BIGLEN_LIMIT = 1024*1024 / SIZEOF_BDIGITS;
@@ -2050,7 +2062,7 @@
 	    }
 	    return bignorm(z);
 	}
-	d = (double)yy;
+	/* NOTREACHED */
 	break;
 
       default:
@@ -2590,7 +2602,8 @@
     rb_define_method(rb_cBignum, "modulo", rb_big_modulo, 1);
     rb_define_method(rb_cBignum, "remainder", rb_big_remainder, 1);
     rb_define_method(rb_cBignum, "quo", rb_big_quo, 1);
-    rb_define_method(rb_cBignum, "fdiv", rb_big_quo, 1);
+    rb_define_method(rb_cBignum, "rdiv", rb_big_quo, 1);
+    rb_define_method(rb_cBignum, "fdiv", rb_big_fdiv, 1);
     rb_define_method(rb_cBignum, "**", rb_big_pow, 1);
     rb_define_method(rb_cBignum, "&", rb_big_and, 1);
     rb_define_method(rb_cBignum, "|", rb_big_or, 1);
Index: test/ruby/test_complex.rb
===================================================================
--- test/ruby/test_complex.rb	(revision 0)
+++ test/ruby/test_complex.rb	(revision 15783)
@@ -0,0 +1,1017 @@
+require 'test/unit'
+
+class ComplexSub < Complex; end
+
+class Complex_Test < Test::Unit::TestCase
+
+  def test_sub
+    c = ComplexSub.__send__(:new, 1)
+    cc = ComplexSub.__send__(:convert, 1)
+    if defined?(ComplexSub::Unify)
+      assert_instance_of(Fixnum, c)
+      assert_instance_of(Fixnum, cc)
+    else
+      assert_instance_of(ComplexSub, c)
+      assert_instance_of(ComplexSub, cc)
+
+      c2 = c + 1
+      assert_instance_of(ComplexSub, c2)
+      c2 = c - 1
+      assert_instance_of(ComplexSub, c2)
+
+      c3 = c - c2
+      assert_instance_of(ComplexSub, c3)
+
+      s = Marshal.dump(c)
+      c5 = Marshal.load(s)
+      assert_equal(c, c5)
+      assert_instance_of(ComplexSub, c5)
+    end
+
+  end
+
+  def test_eql_p
+    c = Complex(0)
+    c2 = Complex(0)
+    c3 = Complex(1)
+
+    assert_equal(true, c.eql?(c2))
+    assert_equal(false, c.eql?(c3))
+
+    if defined?(Complex::Unify)
+      assert_equal(true, c.eql?(0))
+    else
+      assert_equal(false, c.eql?(0))
+    end
+  end
+
+  def test_hash
+    assert_instance_of(Fixnum, Complex(1,2).hash)
+
+    h = {}
+    h[Complex(0)] = 0
+    h[Complex(0,1)] = 1
+    h[Complex(1,0)] = 2
+    h[Complex(1,1)] = 3
+
+    assert_equal(4, h.size)
+    assert_equal(2, h[Complex(1,0)])
+
+    h[Complex(0,0)] = 9
+    assert_equal(4, h.size)
+  end
+
+  def test_freeze
+    c = Complex(1)
+    c.freeze
+    unless defined?(Complex::Unify)
+      assert_equal(true, c.frozen?)
+    end
+    assert_instance_of(String, c.to_s)
+  end
+
+  def test_new_bang # no unify
+    assert_instance_of(Complex, Complex.__send__(:new!, 2,0))
+    assert_equal([2,0], Complex.__send__(:new!, 2,0).
+		 instance_eval{[real, image]})
+    assert_equal([2,4], Complex.__send__(:new!, 2,4).
+		 instance_eval{[real, image]})
+    assert_equal([-2,4], Complex.__send__(:new!, -2,4).
+		 instance_eval{[real, image]})
+    assert_equal([2,-4], Complex.__send__(:new!, 2,-4).
+		 instance_eval{[real, image]})
+    assert_equal([-2,-4], Complex.__send__(:new!, -2,-4).
+		 instance_eval{[real, image]})
+
+    assert_equal([2,0], Complex.__send__(:new!, Complex(2)).
+		 instance_eval{[real, image]})
+    assert_equal([2,3], Complex.__send__(:new!, Complex(2), Complex(3)).
+		 instance_eval{[real, image]})
+    assert_equal([2,3], Complex.__send__(:new!, 2, Complex(3)).
+		 instance_eval{[real, image]})
+
+    assert_equal([1.1,0], Complex.__send__(:new!, 1.1).
+		 instance_eval{[real, image]})
+    assert_equal([-1.1,0], Complex.__send__(:new!, -1.1).
+		 instance_eval{[real, image]})
+    assert_equal([1,0], Complex.__send__(:new!, '1').
+		 instance_eval{[real, image]})
+    assert_equal([0,0], Complex.__send__(:new!, nil).
+		 instance_eval{[real, image]})
+  end
+
+  def test_new
+    if defined?(Complex::Unify)
+      assert_instance_of(Fixnum, Complex.__send__(:new, 2,0))
+    else
+      assert_instance_of(Complex, Complex.__send__(:new, 2,0))
+      assert_equal([2,0], Complex.__send__(:new, 2,0). instance_eval{[real, image]})
+    end
+    assert_equal([2,4], Complex.__send__(:new, 2,4).instance_eval{[real, image]})
+    assert_equal([-2,4], Complex.__send__(:new, -2,4).instance_eval{[real, image]})
+    assert_equal([2,-4], Complex.__send__(:new, 2,-4).instance_eval{[real, image]})
+    assert_equal([-2,-4], Complex.__send__(:new, -2,-4).instance_eval{[real, image]})
+
+    assert_raise(ArgumentError){Complex.__send__(:new, Complex(1,2),2)}
+    assert_raise(ArgumentError){Complex.__send__(:new, 2,Complex(1,2))}
+    assert_raise(ArgumentError){Complex.__send__(:new, Complex(1,2),Complex(1,2))}
+
+    assert_raise(ArgumentError){Complex.__send__(:new, '1')}
+    assert_raise(ArgumentError){Complex.__send__(:new, nil)}
+=begin
+    assert_raise(ArgumentError){Complex.__send__(:new, Complex(1))}
+=end
+  end
+
+  def test_conv
+    c = Complex(0,0)
+    assert_equal(Complex.__send__(:new, 0,0), c)
+
+    c = Complex(2**32, 2**32)
+    assert_equal(Complex.__send__(:new, 2**32,2**32), c)
+    assert_equal([2**32,2**32], [c.real,c.image])
+
+    c = Complex(-2**32, 2**32)
+    assert_equal(Complex.__send__(:new, -2**32,2**32), c)
+    assert_equal([-2**32,2**32], [c.real,c.image])
+
+    c = Complex(2**32, -2**32)
+    assert_equal(Complex.__send__(:new, 2**32,-2**32), c)
+    assert_equal([2**32,-2**32], [c.real,c.image])
+
+    c = Complex(-2**32, -2**32)
+    assert_equal(Complex.__send__(:new, -2**32,-2**32), c)
+    assert_equal([-2**32,-2**32], [c.real,c.image])
+
+    c = Complex(Complex(1),0)
+    assert_equal(Complex.__send__(:new, 1,0), c)
+
+    c = Complex(0,Complex(1))
+    assert_equal(Complex.__send__(:new, 0,1), c)
+
+    c = 5.re
+    assert_equal(Complex.__send__(:new, 5,0), c)
+
+    c = Complex(1,2).re
+    assert_equal(Complex.__send__(:new, 1,2), c)
+
+    c = 5.im
+    assert_equal(Complex.__send__(:new, 0,5), c)
+
+    c = Complex(2,0).im
+    assert_equal(Complex.__send__(:new, 0,2), c)
+    assert_raise(ArgumentError){Complex(1,2).im}
+
+    c = Complex::I
+    assert_equal(Complex.__send__(:new, 0,1), c)
+
+    assert_equal(Complex.__send__(:new, 1),Complex(1))
+    assert_equal(Complex.__send__(:new, 1),Complex('1'))
+    assert_raise(ArgumentError){Complex(nil)}
+  end
+
+  def test_attr
+    c = Complex(4)
+
+    assert_equal(4, c.real)
+    assert_equal(0, c.image)
+
+    c = Complex(4,5)
+
+    assert_equal(4, c.real)
+    assert_equal(5, c.image)
+
+    c = Complex(-0.0,-0.0)
+
+    assert_equal('-0.0', c.real.to_s)
+    assert_equal('-0.0', c.image.to_s)
+
+    c = Complex.__send__(:new, 4)
+
+    assert_equal(4, c.real)
+    assert_equal(0, c.image)
+    assert_equal(c.imag, c.image)
+
+    c = Complex.__send__(:new, 4,5)
+
+    assert_equal(4, c.real)
+    assert_equal(5, c.image)
+    assert_equal(c.imag, c.image)
+
+    c = Complex.__send__(:new, -0.0,-0.0)
+
+    assert_equal('-0.0', c.real.to_s)
+    assert_equal('-0.0', c.image.to_s)
+    assert_equal(c.imag.to_s, c.image.to_s)
+
+    c = Complex.__send__(:new!, 4)
+
+    assert_equal(4, c.real)
+    assert_equal(c.imag, c.image)
+    assert_equal(0, c.image)
+
+    c = Complex.__send__(:new!, 4,5)
+
+    assert_equal(4, c.real)
+    assert_equal(5, c.image)
+    assert_equal(c.imag, c.image)
+
+    c = Complex.__send__(:new!, -0.0,-0.0)
+
+    assert_equal('-0.0', c.real.to_s)
+    assert_equal('-0.0', c.image.to_s)
+    assert_equal(c.imag.to_s, c.image.to_s)
+  end
+
+  def test_attr2
+    c = Complex(1)
+
+    if defined?(Complex::Unify)
+      assert_equal(true, c.scalar?)
+=begin
+      assert_equal(true, c.finite?)
+      assert_equal(false, c.infinite?)
+      assert_equal(false, c.nan?)
+      assert_equal(true, c.integer?)
+      assert_equal(false, c.float?)
+      assert_equal(true, c.rational?)
+      assert_equal(true, c.real?)
+      assert_equal(false, c.complex?)
+      assert_equal(true, c.exact?)
+      assert_equal(false, c.inexact?)
+=end
+    else
+      assert_equal(false, c.scalar?)
+=begin
+      assert_equal(true, c.finite?)
+      assert_equal(false, c.infinite?)
+      assert_equal(false, c.nan?)
+      assert_equal(false, c.integer?)
+      assert_equal(false, c.float?)
+      assert_equal(false, c.rational?)
+      assert_equal(false, c.real?)
+      assert_equal(true, c.complex?)
+      assert_equal(true, c.exact?)
+      assert_equal(false, c.inexact?)
+=end
+    end
+
+=begin
+    assert_equal(0, Complex(0).sign)
+    assert_equal(1, Complex(2).sign)
+    assert_equal(-1, Complex(-2).sign)
+=end
+
+    assert_equal(true, Complex(0).zero?)
+    assert_equal(true, Complex(0,0).zero?)
+    assert_equal(false, Complex(1,0).zero?)
+    assert_equal(false, Complex(0,1).zero?)
+    assert_equal(false, Complex(1,1).zero?)
+
+    assert_equal(nil, Complex(0).nonzero?)
+    assert_equal(nil, Complex(0,0).nonzero?)
+    assert_equal(Complex(1,0), Complex(1,0).nonzero?)
+    assert_equal(Complex(0,1), Complex(0,1).nonzero?)
+    assert_equal(Complex(1,1), Complex(1,1).nonzero?)
+  end
+
+  def test_uplus
+    assert_equal(Complex(1), +Complex(1))
+    assert_equal(Complex(-1), +Complex(-1))
+    assert_equal(Complex(1,1), +Complex(1,1))
+    assert_equal(Complex(-1,1), +Complex(-1,1))
+    assert_equal(Complex(1,-1), +Complex(1,-1))
+    assert_equal(Complex(-1,-1), +Complex(-1,-1))
+  end
+
+  def test_negate
+    assert_equal(Complex(-1), -Complex(1))
+    assert_equal(Complex(1), -Complex(-1))
+    assert_equal(Complex(-1,-1), -Complex(1,1))
+    assert_equal(Complex(1,-1), -Complex(-1,1))
+    assert_equal(Complex(-1,1), -Complex(1,-1))
+    assert_equal(Complex(1,1), -Complex(-1,-1))
+
+=begin
+    assert_equal(0, Complex(0).negate)
+    assert_equal(-2, Complex(2).negate)
+    assert_equal(2, Complex(-2).negate)
+=end
+  end
+
+  def test_add
+    c = Complex(1,2)
+    c2 = Complex(2,3)
+
+    assert_equal(Complex(3,5), c + c2)
+
+    assert_equal(Complex(3,2), c + 2)
+    assert_equal(Complex(3.0,2), c + 2.0)
+
+    if defined?(Rational)
+      assert_equal(Complex(Rational(3,1),Rational(2)), c + Rational(2))
+      assert_equal(Complex(Rational(5,3),Rational(2)), c + Rational(2,3))
+    end
+  end
+
+  def test_sub
+    c = Complex(1,2)
+    c2 = Complex(2,3)
+
+    assert_equal(Complex(-1,-1), c - c2)
+
+    assert_equal(Complex(-1,2), c - 2)
+    assert_equal(Complex(-1.0,2), c - 2.0)
+
+    if defined?(Rational)
+      assert_equal(Complex(Rational(-1,1),Rational(2)), c - Rational(2))
+      assert_equal(Complex(Rational(1,3),Rational(2)), c - Rational(2,3))
+    end
+  end
+
+  def test_mul
+    c = Complex(1,2)
+    c2 = Complex(2,3)
+
+    assert_equal(Complex(-4,7), c * c2)
+
+    assert_equal(Complex(2,4), c * 2)
+    assert_equal(Complex(2.0,4.0), c * 2.0)
+
+    if defined?(Rational)
+      assert_equal(Complex(Rational(2,1),Rational(4)), c * Rational(2))
+      assert_equal(Complex(Rational(2,3),Rational(4,3)), c * Rational(2,3))
+    end
+
+  end
+
+  def test_div
+    c = Complex(1,2)
+    c2 = Complex(2,3)
+
+    if defined?(Complex::Unify)
+      assert_equal(Complex(Rational(8,13),Rational(1,13)), c / c2)
+    else
+      assert_equal(Complex(0,0), c / c2)
+    end
+
+    c = Complex(1.0,2.0)
+    c2 = Complex(2.0,3.0)
+
+    r = c / c2
+    assert_in_delta(0.615, r.real, 0.001)
+    assert_in_delta(0.076, r.image, 0.001)
+
+    c = Complex(1,2)
+    c2 = Complex(2,3)
+
+    if defined?(Complex::Unify)
+      assert_equal(Complex(Rational(1,2),1), c / 2)
+    else
+      assert_equal(Complex(0,1), c / 2)
+    end
+    assert_equal(Complex(0.5,1.0), c / 2.0)
+
+    if defined?(Rational)
+      assert_equal(Complex(Rational(1,2),Rational(1)), c / Rational(2))
+      assert_equal(Complex(Rational(3,2),Rational(3)), c / Rational(2,3))
+    end
+  end
+
+  def test_quo
+    c = Complex(1,2)
+    c2 = Complex(2,3)
+
+    if defined?(Rational)
+      assert_equal(Complex(Rational(8,13),Rational(1,13)), c.quo(c2))
+    else
+      r = c.quo(c2)
+      assert_in_delta(0.615, r.real, 0.001)
+      assert_in_delta(0.076, r.image, 0.001)
+    end
+
+    c = Complex(1.0,2.0)
+    c2 = Complex(2.0,3.0)
+
+    r = c.quo(c2)
+    assert_in_delta(0.615, r.real, 0.001)
+    assert_in_delta(0.076, r.image, 0.001)
+
+    c = Complex(1,2)
+    c2 = Complex(2,3)
+
+    if defined?(Rational)
+      assert_equal(Complex(Rational(1,2),1), c.quo(2))
+    else
+      assert_equal(Complex(0.5,1.0), c.quo(2))
+    end
+    assert_equal(Complex(0.5,1.0), c.quo(2.0))
+
+    if defined?(Rational)
+      assert_equal(Complex(Rational(1,2),Rational(1)), c / Rational(2))
+      assert_equal(Complex(Rational(3,2),Rational(3)), c / Rational(2,3))
+    end
+  end
+
+  def test_rdiv
+    if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID')
+      c = Complex(1,2)
+      c2 = Complex(2,3)
+
+      assert_equal(Complex(Rational(8,13),Rational(1,13)), c.rdiv(c2))
+
+      c = Complex(1.0,2.0)
+      c2 = Complex(2.0,3.0)
+
+      r = c.rdiv(c2)
+      assert_in_delta(0.615, r.real, 0.001)
+      assert_in_delta(0.076, r.image, 0.001)
+
+      c = Complex(1,2)
+      c2 = Complex(2,3)
+
+      assert_equal(Complex(Rational(1,2),1), c.rdiv(2))
+
+      assert_equal(Complex(Rational(1,2),Rational(1)), c / Rational(2))
+      assert_equal(Complex(Rational(3,2),Rational(3)), c / Rational(2,3))
+    end
+  end
+
+  def test_fdiv
+    c = Complex(1,2)
+    c2 = Complex(2,3)
+
+    r = c.fdiv(c2)
+    assert_in_delta(0.615, r.real, 0.001)
+    assert_in_delta(0.076, r.image, 0.001)
+
+    c = Complex(1.0,2.0)
+    c2 = Complex(2.0,3.0)
+
+    r = c.fdiv(c2)
+    assert_in_delta(0.615, r.real, 0.001)
+    assert_in_delta(0.076, r.image, 0.001)
+
+    c = Complex(1,2)
+    c2 = Complex(2,3)
+
+    assert_equal(Complex(0.5,1.0), c.fdiv(2))
+    assert_equal(Complex(0.5,1.0), c.fdiv(2.0))
+  end
+
+  def test_expt
+    c = Complex(1,2)
+    c2 = Complex(2,3)
+
+    r = c ** c2
+    assert_in_delta(-0.015, r.real, 0.001)
+    assert_in_delta(-0.179, r.image, 0.001)
+
+    assert_equal(Complex(-3,4), c ** 2)
+    if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID')
+      assert_equal(Complex(Rational(-3,25),Rational(-4,25)), c ** -2)
+    else
+      r = c ** -2
+      assert_in_delta(-0.12, r.real, 0.001)
+      assert_in_delta(-0.16, r.image, 0.001)
+    end
+    r = c ** 2.0
+    assert_in_delta(-3.0, r.real, 0.001)
+    assert_in_delta(4.0, r.image, 0.001)
+
+    r = c ** -2.0
+    assert_in_delta(-0.12, r.real, 0.001)
+    assert_in_delta(-0.16, r.image, 0.001)
+
+    if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID')
+      assert_equal(Complex(-3,4), c ** Rational(2))
+#=begin
+      assert_equal(Complex(Rational(-3,25),Rational(-4,25)),
+		   c ** Rational(-2)) # why failed?
+#=end
+
+      r = c ** Rational(2,3)
+      assert_in_delta(1.264, r.real, 0.001)
+      assert_in_delta(1.150, r.image, 0.001)
+
+      r = c ** Rational(-2,3)
+      assert_in_delta(0.432, r.real, 0.001)
+      assert_in_delta(-0.393, r.image, 0.001)
+    end
+  end
+
+  def test_cmp
+    assert_raise(NoMethodError){1 <=> Complex(1,1)}
+    assert_raise(NoMethodError){Complex(1,1) <=> 1}
+    assert_raise(NoMethodError){Complex(1,1) <=> Complex(1,1)}
+  end
+
+  def test_equal
+    assert(Complex(1,0) == Complex(1))
+    assert(Complex(1,0) == Complex.__send__(:new, 1))
+    assert(Complex(1,0) == Complex.__send__(:new, 1,0))
+    assert(Complex(1,0) == Complex.__send__(:new!, 1))
+    assert(Complex(1,0) == Complex.__send__(:new!, 1,0))
+
+    assert(Complex(-1,0) == Complex(-1))
+    assert(Complex(-1,0) == Complex.__send__(:new, -1))
+    assert(Complex(-1,0) == Complex.__send__(:new, -1,0))
+    assert(Complex(-1,0) == Complex.__send__(:new!, -1))
+    assert(Complex(-1,0) == Complex.__send__(:new!, -1,0))
+
+    assert_equal(false, Complex(2,1) == Complex(1))
+    assert_equal(true, Complex(2,1) != Complex(1))
+    assert_equal(false, Complex(1) == nil)
+    assert_equal(false, Complex(1) == '')
+  end
+
+  def test_math
+    c = Complex(1,2)
+
+    assert_in_delta(2.236, c.abs, 0.001)
+    assert_equal(5, c.abs2)
+
+    assert_equal(c.abs, Math.sqrt(c * c.conj))
+    assert_equal(c.abs, Math.sqrt(c.real**2 + c.image**2))
+    assert_equal(c.abs2, c * c.conj)
+    assert_equal(c.abs2, c.real**2 + c.image**2)
+
+    assert_in_delta(1.107, c.arg, 0.001)
+    assert_in_delta(1.107, c.angle, 0.001)
+
+    r = c.polar
+    assert_in_delta(2.236, r[0], 0.001)
+    assert_in_delta(1.107, r[1], 0.001)
+    assert_equal(Complex(1,-2), c.conjugate)
+    assert_equal(Complex(1,-2), c.conj)
+#    assert_equal(Complex(1,-2), ~c)
+#    assert_equal(5, c * ~c)
+
+    assert_equal(Complex(1,2), c.numerator)
+    assert_equal(1, c.denominator)
+  end
+
+  def test_to_s
+    c = Complex(1,2)
+
+    assert_instance_of(String, c.to_s)
+    assert_equal('1+2i', c.to_s)
+
+    assert_equal('2i', Complex(0,2).to_s)
+    assert_equal('-2i', Complex(0,-2).to_s)
+    assert_equal('1+2i', Complex(1,2).to_s)
+    assert_equal('-1+2i', Complex(-1,2).to_s)
+    assert_equal('-1-2i', Complex(-1,-2).to_s)
+    assert_equal('1-2i', Complex(1,-2).to_s)
+    assert_equal('-1-2i', Complex(-1,-2).to_s)
+
+    assert_equal('2.0i', Complex(0,2.0).to_s)
+    assert_equal('-2.0i', Complex(0,-2.0).to_s)
+    assert_equal('1.0+2.0i', Complex(1.0,2.0).to_s)
+    assert_equal('-1.0+2.0i', Complex(-1.0,2.0).to_s)
+    assert_equal('-1.0-2.0i', Complex(-1.0,-2.0).to_s)
+    assert_equal('1.0-2.0i', Complex(1.0,-2.0).to_s)
+    assert_equal('-1.0-2.0i', Complex(-1.0,-2.0).to_s)
+
+    if defined?(Rational)
+      assert_equal('2i', Complex(0,Rational(2)).to_s)
+      assert_equal('-2i', Complex(0,Rational(-2)).to_s)
+      assert_equal('1+2i', Complex(1,Rational(2)).to_s)
+      assert_equal('-1+2i', Complex(-1,Rational(2)).to_s)
+      assert_equal('-1-2i', Complex(-1,Rational(-2)).to_s)
+      assert_equal('1-2i', Complex(1,Rational(-2)).to_s)
+      assert_equal('-1-2i', Complex(-1,Rational(-2)).to_s)
+
+      assert_equal('(2/3)i', Complex(0,Rational(2,3)).to_s)
+      assert_equal('(-2/3)i', Complex(0,Rational(-2,3)).to_s)
+      assert_equal('1+(2/3)i', Complex(1,Rational(2,3)).to_s)
+      assert_equal('-1+(2/3)i', Complex(-1,Rational(2,3)).to_s)
+      assert_equal('-1-(2/3)i', Complex(-1,Rational(-2,3)).to_s)
+      assert_equal('1-(2/3)i', Complex(1,Rational(-2,3)).to_s)
+      assert_equal('-1-(2/3)i', Complex(-1,Rational(-2,3)).to_s)
+    end
+  end
+
+  def test_inspect
+    c = Complex(1,2)
+
+    assert_instance_of(String, c.inspect)
+    assert_equal('Complex(1, 2)', c.inspect)
+  end
+
+  def test_marshal
+    c = Complex(1,2)
+
+    s = Marshal.dump(c)
+    c2 = Marshal.load(s)
+    assert_equal(c, c2)
+    assert_instance_of(Complex, c2)
+
+    if defined?(Rational)
+      c = Complex(Rational(1,2),Rational(2,3))
+
+      s = Marshal.dump(c)
+      c2 = Marshal.load(s)
+      assert_equal(c, c2)
+      assert_instance_of(Complex, c2)
+    end
+  end
+
+  def test_parse
+    assert_equal(Complex(0), ''.to_c)
+    assert_equal(Complex(0), ' '.to_c)
+    assert_equal(Complex(5), '5'.to_c)
+    assert_equal(Complex(-5), '-5'.to_c)
+    assert_equal(Complex(5,3), '5+3i'.to_c)
+    assert_equal(Complex(-5,3), '-5+3i'.to_c)
+    assert_equal(Complex(5,-3), '5-3i'.to_c)
+    assert_equal(Complex(-5,-3), '-5-3i'.to_c)
+    assert_equal(Complex(0,3), '3i'.to_c)
+    assert_equal(Complex(0,-3), '-3i'.to_c)
+
+    assert_equal(Complex(5,3), '5+3I'.to_c)
+    assert_equal(Complex(5,3), '5+3j'.to_c)
+    assert_equal(Complex(5,3), '5+3J'.to_c)
+    assert_equal(Complex(0,3), '3I'.to_c)
+    assert_equal(Complex(0,3), '3j'.to_c)
+    assert_equal(Complex(0,3), '3J'.to_c)
+
+    assert_equal(Complex(5.0), '5.0'.to_c)
+    assert_equal(Complex(-5.0), '-5.0'.to_c)
+    assert_equal(Complex(5.0,3.0), '5.0+3.0i'.to_c)
+    assert_equal(Complex(-5.0,3.0), '-5.0+3.0i'.to_c)
+    assert_equal(Complex(5.0,-3.0), '5.0-3.0i'.to_c)
+    assert_equal(Complex(-5.0,-3.0), '-5.0-3.0i'.to_c)
+    assert_equal(Complex(0.0,3.0), '3.0i'.to_c)
+    assert_equal(Complex(0.0,-3.0), '-3.0i'.to_c)
+
+    assert_equal(Complex(5.0), '5e0'.to_c)
+    assert_equal(Complex(-5.0), '-5e0'.to_c)
+    assert_equal(Complex(5.0,3.0), '5e0+3e0i'.to_c)
+    assert_equal(Complex(-5.0,3.0), '-5e0+3e0i'.to_c)
+    assert_equal(Complex(5.0,-3.0), '5e0-3e0i'.to_c)
+    assert_equal(Complex(-5.0,-3.0), '-5e0-3e0i'.to_c)
+    assert_equal(Complex(0.0,3.0), '3e0i'.to_c)
+    assert_equal(Complex(0.0,-3.0), '-3e0i'.to_c)
+
+    assert_equal(Complex(5), Complex('5'))
+    assert_equal(Complex(-5), Complex('-5'))
+    assert_equal(Complex(5,3), Complex('5+3i'))
+    assert_equal(Complex(-5,3), Complex('-5+3i'))
+    assert_equal(Complex(5,-3), Complex('5-3i'))
+    assert_equal(Complex(-5,-3), Complex('-5-3i'))
+    assert_equal(Complex(0,3), Complex('3i'))
+    assert_equal(Complex(0,-3), Complex('-3i'))
+
+    assert_equal(Complex(5,3), Complex('5+3I'))
+    assert_equal(Complex(5,3), Complex('5+3j'))
+    assert_equal(Complex(5,3), Complex('5+3J'))
+    assert_equal(Complex(0,3), Complex('3I'))
+    assert_equal(Complex(0,3), Complex('3j'))
+    assert_equal(Complex(0,3), Complex('3J'))
+
+    assert_equal(Complex(5.0), Complex('5.0'))
+    assert_equal(Complex(-5.0), Complex('-5.0'))
+    assert_equal(Complex(5.0,3.0), Complex('5.0+3.0i'))
+    assert_equal(Complex(-5.0,3.0), Complex('-5.0+3.0i'))
+    assert_equal(Complex(5.0,-3.0), Complex('5.0-3.0i'))
+    assert_equal(Complex(-5.0,-3.0), Complex('-5.0-3.0i'))
+    assert_equal(Complex(0.0,3.0), Complex('3.0i'))
+    assert_equal(Complex(0.0,-3.0), Complex('-3.0i'))
+
+    assert_equal(Complex(5.0), Complex('5e0'))
+    assert_equal(Complex(-5.0), Complex('-5e0'))
+    assert_equal(Complex(5.0,3.0), Complex('5e0+3e0i'))
+    assert_equal(Complex(-5.0,3.0), Complex('-5e0+3e0i'))
+    assert_equal(Complex(5.0,-3.0), Complex('5e0-3e0i'))
+    assert_equal(Complex(-5.0,-3.0), Complex('-5e0-3e0i'))
+    assert_equal(Complex(0.0,3.0), Complex('3e0i'))
+    assert_equal(Complex(0.0,-3.0), Complex('-3e0i'))
+
+    assert_equal(Complex(0), '_'.to_c)
+    assert_equal(Complex(0), '_5'.to_c)
+    assert_equal(Complex(5), '5_'.to_c)
+    assert_equal(Complex(5), '5x'.to_c)
+    assert_equal(Complex(5), '5+_3i'.to_c)
+    assert_equal(Complex(5), '5+3_i'.to_c)
+    assert_equal(Complex(5,3), '5+3i_'.to_c)
+    assert_equal(Complex(5,3), '5+3ix'.to_c)
+    assert_raise(ArgumentError){ Complex('')}
+    assert_raise(ArgumentError){ Complex('_')}
+    assert_raise(ArgumentError){ Complex('_5')}
+    assert_raise(ArgumentError){ Complex('5_')}
+    assert_raise(ArgumentError){ Complex('5x')}
+    assert_raise(ArgumentError){ Complex('5+_3i')}
+    assert_raise(ArgumentError){ Complex('5+3_i')}
+    assert_raise(ArgumentError){ Complex('5+3i_')}
+    assert_raise(ArgumentError){ Complex('5+3ix')}
+
+    if defined?(Rational) && defined?(''.to_r)
+      assert_equal(Complex(Rational(1,5)), '1/5'.to_c)
+      assert_equal(Complex(Rational(-1,5)), '-1/5'.to_c)
+      assert_equal(Complex(Rational(1,5),3), '1/5+3i'.to_c)
+      assert_equal(Complex(Rational(1,5),-3), '1/5-3i'.to_c)
+      assert_equal(Complex(Rational(-1,5),3), '-1/5+3i'.to_c)
+      assert_equal(Complex(Rational(-1,5),-3), '-1/5-3i'.to_c)
+      assert_equal(Complex(Rational(1,5),Rational(3,2)), '1/5+3/2i'.to_c)
+      assert_equal(Complex(Rational(1,5),Rational(-3,2)), '1/5-3/2i'.to_c)
+      assert_equal(Complex(Rational(-1,5),Rational(3,2)), '-1/5+3/2i'.to_c)
+      assert_equal(Complex(Rational(-1,5),Rational(-3,2)), '-1/5-3/2i'.to_c)
+      assert_equal(Complex(Rational(1,5),Rational(3,2)), '1/5+(3/2)i'.to_c)
+      assert_equal(Complex(Rational(1,5),Rational(-3,2)), '1/5-(3/2)i'.to_c)
+      assert_equal(Complex(Rational(-1,5),Rational(3,2)), '-1/5+(3/2)i'.to_c)
+      assert_equal(Complex(Rational(-1,5),Rational(-3,2)), '-1/5-(3/2)i'.to_c)
+    end
+
+  end
+
+  def test_respond
+    c = Complex(1,1)
+    assert_equal(false, c.respond_to?(:<))
+    assert_equal(false, c.respond_to?(:<=))
+    assert_equal(false, c.respond_to?(:<=>))
+    assert_equal(false, c.respond_to?(:>))
+    assert_equal(false, c.respond_to?(:>=))
+    assert_equal(false, c.respond_to?(:between?))
+#    assert_equal(false, c.respond_to?(:div)) # ?
+    assert_equal(false, c.respond_to?(:divmod))
+    assert_equal(false, c.respond_to?(:floor))
+    assert_equal(false, c.respond_to?(:ceil))
+    assert_equal(false, c.respond_to?(:modulo))
+    assert_equal(false, c.respond_to?(:round))
+    assert_equal(false, c.respond_to?(:step))
+    assert_equal(false, c.respond_to?(:tunrcate))
+
+    assert_equal(false, c.respond_to?(:positive?))
+    assert_equal(false, c.respond_to?(:negative?))
+#    assert_equal(false, c.respond_to?(:sign))
+
+    assert_equal(false, c.respond_to?(:quotient))
+    assert_equal(false, c.respond_to?(:quot))
+    assert_equal(false, c.respond_to?(:quotrem))
+
+    assert_equal(false, c.respond_to?(:gcd))
+    assert_equal(false, c.respond_to?(:lcm))
+    assert_equal(false, c.respond_to?(:gcdlcm))
+  end
+
+  def test_to_i
+    assert_equal(3, Complex(3).to_i)
+    assert_equal(3, Integer(Complex(3)))
+    assert_raise(RangeError){Complex(3,2).to_i}
+    assert_raise(RangeError){Integer(Complex(3,2))}
+  end
+
+  def test_to_f
+    assert_equal(3.0, Complex(3).to_f)
+    assert_equal(3.0, Float(Complex(3)))
+    assert_raise(RangeError){Complex(3,2).to_f}
+    assert_raise(RangeError){Float(Complex(3,2))}
+  end
+
+  def test_to_r
+    if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID')
+      assert_equal(Rational(3), Complex(3).to_r)
+      assert_equal(Rational(3), Rational(Complex(3)))
+      assert_raise(RangeError){Complex(3,2).to_r}
+      assert_raise(RangeError){Rational(Complex(3,2))}
+    end
+  end
+
+  def test_to_c
+    c = nil.to_c
+    assert_equal([0,0] , [c.real, c.image])
+
+    c = 0.to_c
+    assert_equal([0,0] , [c.real, c.image])
+
+    c = 1.to_c
+    assert_equal([1,0] , [c.real, c.image])
+
+    c = 1.1.to_c
+    assert_equal([1.1, 0], [c.real, c.image])
+
+    if defined?(Rational)
+      c = Rational(1,2).to_c
+      assert_equal([Rational(1,2), 0], [c.real, c.image])
+    end
+
+    c = Complex(1,2).to_c
+    assert_equal([1, 2], [c.real, c.image])
+  end
+
+  def test_prec
+    assert_equal(nil, Complex < Precision)
+  end
+
+  def test_supp
+    assert_equal(true, 1.scalar?)
+    assert_equal(true, 1.1.scalar?)
+
+    assert_equal(1, 1.real)
+    assert_equal(0, 1.image)
+    assert_equal(0, 1.imag)
+
+    assert_equal(1.1, 1.1.real)
+    assert_equal(0, 1.1.image)
+    assert_equal(0, 1.1.imag)
+
+    assert_equal(0, 1.arg)
+    assert_equal(0, 1.angle)
+
+    assert_equal(0, 1.0.arg)
+    assert_equal(0, 1.0.angle)
+
+    assert_equal(Math::PI, -1.arg)
+    assert_equal(Math::PI, -1.angle)
+
+    assert_equal(Math::PI, -1.0.arg)
+    assert_equal(Math::PI, -1.0.angle)
+
+    assert_equal([1,0], 1.polar)
+    assert_equal([1, Math::PI], -1.polar)
+
+    assert_equal([1.0,0], 1.0.polar)
+    assert_equal([1.0, Math::PI], -1.0.polar)
+
+    assert_equal(1, 1.conjugate)
+    assert_equal(-1, -1.conjugate)
+    assert_equal(1, 1.conj)
+    assert_equal(-1, -1.conj)
+
+    assert_equal(1.1, 1.1.conjugate)
+    assert_equal(-1.1, -1.1.conjugate)
+    assert_equal(1.1, 1.1.conj)
+    assert_equal(-1.1, -1.1.conj)
+
+    assert_equal(1, 1.numerator)
+    assert_equal(9, 9.numerator)
+    assert_equal(1, 1.denominator)
+    assert_equal(1, 9.denominator)
+
+    if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID')
+      assert_equal(1.0, 1.0.numerator)
+      assert_equal(9.0, 9.0.numerator)
+      assert_equal(1.0, 1.0.denominator)
+      assert_equal(1.0, 9.0.denominator)
+    end
+
+=begin
+    if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID')
+      assert_equal(Rational(1,9), 9.reciprocal)
+      assert_equal(Rational(1,9), 9.0.reciprocal)
+      assert_equal(Rational(1,9), 9.inverse)
+      assert_equal(Rational(1,9), 9.0.inverse)
+    end
+=end
+
+    if defined?(Rational)
+      assert_equal(Rational(1,2), 1.quo(2))
+      assert_equal(Rational(5000000000), 10000000000.quo(2))
+      assert_equal(0.5, 1.0.quo(2))
+      assert_equal(Rational(1,4), Rational(1,2).quo(2))
+      assert_equal(Complex(Rational(1,2),Rational(1)), Complex(1,2).quo(2))
+    else
+      assert_equal(0.5, 1.quo(2))
+      assert_equal(5000000000.0, 10000000000.quo(2))
+      assert_equal(0.5, 1.0.quo(2))
+      assert_equal(Complex(0.5,1.0), Complex(1,2).quo(2))
+    end
+
+    if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID')
+      assert_equal(Rational(1,2), 1.rdiv(2))
+      assert_equal(Rational(5000000000), 10000000000.rdiv(2))
+      assert_equal(Rational(1,2), 1.0.rdiv(2))
+      assert_equal(Rational(1,4), Rational(1,2).rdiv(2))
+      assert_equal(Complex(Rational(1,2),Rational(1)), Complex(1,2).quo(2))
+    end
+
+    assert_equal(0.5, 1.fdiv(2))
+    assert_equal(5000000000.0, 10000000000.fdiv(2))
+    assert_equal(0.5, 1.0.fdiv(2))
+    if defined?(Rational)
+      assert_equal(0.25, Rational(1,2).fdiv(2))
+    end
+    assert_equal(Complex(0.5,1.0), Complex(1,2).quo(2))
+
+    unless $".grep(/complex/).empty?
+      assert_equal(Complex(0,2), Math.sqrt(-4.0))
+#      assert_equal(true, Math.sqrt(-4.0).inexact?)
+      assert_equal(Complex(0,2), Math.sqrt(-4))
+#      assert_equal(true, Math.sqrt(-4).exact?)
+      if defined?(Rational)
+	assert_equal(Complex(0,2), Math.sqrt(Rational(-4)))
+#	assert_equal(true, Math.sqrt(Rational(-4)).exact?)
+      end
+
+      assert_equal(Complex(0,3), Math.sqrt(-9.0))
+#      assert_equal(true, Math.sqrt(-9.0).inexact?)
+      assert_equal(Complex(0,3), Math.sqrt(-9))
+#      assert_equal(true, Math.sqrt(-9).exact?)
+      if defined?(Rational)
+	assert_equal(Complex(0,3), Math.sqrt(Rational(-9)))
+#	assert_equal(true, Math.sqrt(Rational(-9)).exact?)
+      end
+
+      c = Math.sqrt(Complex(1, 2))
+      assert_in_delta(1.272, c.real, 0.001)
+      assert_in_delta(0.786, c.image, 0.001)
+
+      c = Math.sqrt(-9)
+      assert_in_delta(0.0, c.real, 0.001)
+      assert_in_delta(3.0, c.image, 0.001)
+
+      c = Math.exp(Complex(1, 2))
+      assert_in_delta(-1.131, c.real, 0.001)
+      assert_in_delta(2.471, c.image, 0.001)
+
+      c = Math.sin(Complex(1, 2))
+      assert_in_delta(3.165, c.real, 0.001)
+      assert_in_delta(1.959, c.image, 0.001)
+
+      c = Math.cos(Complex(1, 2))
+      assert_in_delta(2.032, c.real, 0.001)
+      assert_in_delta(-3.051, c.image, 0.001)
+
+      c = Math.tan(Complex(1, 2))
+      assert_in_delta(0.033, c.real, 0.001)
+      assert_in_delta(1.014, c.image, 0.001)
+
+      c = Math.sinh(Complex(1, 2))
+      assert_in_delta(-0.489, c.real, 0.001)
+      assert_in_delta(1.403, c.image, 0.001)
+
+      c = Math.cosh(Complex(1, 2))
+      assert_in_delta(-0.642, c.real, 0.001)
+      assert_in_delta(1.068, c.image, 0.001)
+
+      c = Math.tanh(Complex(1, 2))
+      assert_in_delta(1.166, c.real, 0.001)
+      assert_in_delta(-0.243, c.image, 0.001)
+
+      c = Math.log(Complex(1, 2))
+      assert_in_delta(0.804, c.real, 0.001)
+      assert_in_delta(1.107, c.image, 0.001)
+
+      c = Math.log(Complex(1, 2), Math::E)
+      assert_in_delta(0.804, c.real, 0.001)
+      assert_in_delta(1.107, c.image, 0.001)
+
+      c = Math.log(-1)
+      assert_in_delta(0.0, c.real, 0.001)
+      assert_in_delta(Math::PI, c.image, 0.001)
+
+      c = Math.log(8, 2)
+      assert_in_delta(3.0, c.real, 0.001)
+      assert_in_delta(0.0, c.image, 0.001)
+
+      c = Math.log(-8, -2)
+      assert_in_delta(1.092, c.real, 0.001)
+      assert_in_delta(-0.420, c.image, 0.001)
+
+      c = Math.log10(Complex(1, 2))
+      assert_in_delta(0.349, c.real, 0.001)
+      assert_in_delta(0.480, c.image, 0.001)
+
+      c = Math.asin(Complex(1, 2))
+      assert_in_delta(0.427, c.real, 0.001)
+      assert_in_delta(1.528, c.image, 0.001)
+
+      c = Math.acos(Complex(1, 2))
+      assert_in_delta(1.143, c.real, 0.001)
+      assert_in_delta(-1.528, c.image, 0.001)
+
+      c = Math.atan(Complex(1, 2))
+      assert_in_delta(1.338, c.real, 0.001)
+      assert_in_delta(0.402, c.image, 0.001)
+
+      c = Math.atan2(Complex(1, 2), 1)
+      assert_in_delta(1.338, c.real, 0.001)
+      assert_in_delta(0.402, c.image, 0.001)
+
+      c = Math.asinh(Complex(1, 2))
+      assert_in_delta(1.469, c.real, 0.001)
+      assert_in_delta(1.063, c.image, 0.001)
+
+      c = Math.acosh(Complex(1, 2))
+      assert_in_delta(1.528, c.real, 0.001)
+      assert_in_delta(1.143, c.image, 0.001)
+
+      c = Math.atanh(Complex(1, 2))
+      assert_in_delta(0.173, c.real, 0.001)
+      assert_in_delta(1.178, c.image, 0.001)
+    end
+
+  end
+
+  def test_fixed_bug
+    if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID')
+      assert_equal(Complex(1), 1 ** Complex(1))
+    end
+    assert_equal('-1.0-0.0i', Complex(-1.0, -0.0).to_s)
+  end
+
+  def test_known_bug
+  end
+
+end

Property changes on: test/ruby/test_complex.rb
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Index: test/ruby/test_rational.rb
===================================================================
--- test/ruby/test_rational.rb	(revision 0)
+++ test/ruby/test_rational.rb	(revision 15783)
@@ -0,0 +1,971 @@
+require 'test/unit'
+
+class RationalSub < Rational; end
+
+class Rational_Test < Test::Unit::TestCase
+
+  def test_sub
+    c = RationalSub.__send__(:new, 1)
+    cc = RationalSub.__send__(:convert, 1)
+    if defined?(RationalSub::Unify)
+      assert_instance_of(Fixnum, c)
+      assert_instance_of(Fixnum, cc)
+    else
+      assert_instance_of(RationalSub, c)
+      assert_instance_of(RationalSub, cc)
+
+      c2 = c + 1
+      assert_instance_of(RationalSub, c2)
+      c2 = c - 1
+      assert_instance_of(RationalSub, c2)
+
+      c3 = c - c2
+      assert_instance_of(RationalSub, c3)
+
+      s = Marshal.dump(c)
+      c5 = Marshal.load(s)
+      assert_equal(c, c5)
+      assert_instance_of(RationalSub, c5)
+    end
+  end
+
+  def test_hash
+    assert_instance_of(Fixnum, Rational(1,2).hash)
+
+    h = {}
+    h[Rational(0)] = 0
+    h[Rational(1,1)] = 1
+    h[Rational(2,1)] = 2
+    h[Rational(3,1)] = 3
+
+    assert_equal(4, h.size)
+    assert_equal(2, h[Rational(2,1)])
+
+    h[Rational(0,1)] = 9
+    assert_equal(4, h.size)
+  end
+
+  def test_freeze
+    c = Rational(1)
+    c.freeze
+    unless defined?(Rational::Unify)
+      assert_equal(true, c.frozen?)
+    end
+    assert_instance_of(String, c.to_s)
+  end
+
+  def test_new_bang # no unify & no reduce
+    assert_instance_of(Rational, Rational.__send__(:new!, 2,1))
+    assert_equal([2,1], Rational.__send__(:new!, 2,1).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([2,4],  Rational.__send__(:new!, 2,4).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([-2,4], Rational.__send__(:new!, -2,4).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([-2,4], Rational.__send__(:new!, 2,-4).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([2,4], Rational.__send__(:new!, -2,-4).
+		 instance_eval{[numerator, denominator]})
+
+    # to_i
+    assert_equal([2,1], Rational.__send__(:new!, Rational(2)).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([2,3], Rational.__send__(:new!, Rational(2), Rational(3)).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([2,3], Rational.__send__(:new!, 2, Rational(3)).
+		 instance_eval{[numerator, denominator]})
+
+    assert_equal([1,1], Rational.__send__(:new!, 1.1).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([-1,1], Rational.__send__(:new!, -1.1).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([1,1], Rational.__send__(:new!, '1').
+		 instance_eval{[numerator, denominator]})
+    assert_equal([0,1], Rational.__send__(:new!, nil).
+		 instance_eval{[numerator, denominator]})
+  end
+
+=begin
+  def test_reduce
+    if defined?(Rational::Unify)
+      assert_instance_of(Fixnum, Rational.__send__(:reduce, 2,1))
+    else
+      assert_instance_of(Rational, Rational.__send__(:reduce, 2,1))
+      assert_instance_of(Rational, Rational.__send__(:reduce, 2,1))
+    end
+    assert_equal([2,1], Rational.__send__(:reduce, 2,1).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([1,2], Rational.__send__(:reduce, 2,4).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([-1,2], Rational.__send__(:reduce, -2,4).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([-1,2], Rational.__send__(:reduce, 2,-4).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([1,2], Rational.__send__(:reduce, -2,-4).
+		 instance_eval{[numerator, denominator]})
+
+    assert_raise(ArgumentError){Rational.__send__(:reduce, Rational(1,2),2)}
+    assert_raise(ArgumentError){Rational.__send__(:reduce, 2,Rational(1,2))}
+    assert_raise(ArgumentError){Rational.
+      __send__(:reduce, Rational(1,2),Rational(1,2))}
+
+    assert_raise(ArgumentError){Rational.__send__(:reduce, 1.1)}
+    assert_raise(ArgumentError){Rational.__send__(:reduce, -1.1)}
+    assert_raise(ArgumentError){Rational.__send__(:reduce, '1')}
+    assert_raise(ArgumentError){Rational.__send__(:reduce, nil)}
+  end
+=end
+
+  def test_new
+    if defined?(Rational::Unify)
+      assert_instance_of(Fixnum, Rational.__send__(:new, 2,1))
+    else
+      assert_instance_of(Rational, Rational.__send__(:new, 2,1))
+      assert_equal([2,1], Rational.__send__(:new, 2,1).
+		   instance_eval{[numerator, denominator]})
+    end
+    assert_equal([1,2], Rational.__send__(:new, 2,4).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([-1,2], Rational.__send__(:new, -2,4).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([-1,2], Rational.__send__(:new, 2,-4).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([1,2], Rational.__send__(:new, -2,-4).
+		 instance_eval{[numerator, denominator]})
+
+    assert_raise(ArgumentError){Rational.__send__(:new, Rational(1,2),2)}
+    assert_raise(ArgumentError){Rational.__send__(:new, 2,Rational(1,2))}
+    assert_raise(ArgumentError){Rational.__send__(:new, Rational(1,2),Rational(1,2))}
+
+    assert_raise(ArgumentError){Rational.__send__(:new, 1.1)}
+    assert_raise(ArgumentError){Rational.__send__(:new, -1.1)}
+    assert_raise(ArgumentError){Rational.__send__(:new, '1')}
+    assert_raise(ArgumentError){Rational.__send__(:new, nil)}
+=begin
+    assert_raise(ArgumentError){Rational.__send__(:new, Rational(1))}
+    if defined?(Complex)
+      assert_raise(ArgumentError){Rational.__send__(:new, Complex(1))}
+    end
+=end
+  end
+
+  def test_conv
+    c = Rational(0,1)
+    assert_equal(Rational.__send__(:new, 0,1), c)
+
+    c = Rational(2**32, 2**32)
+    assert_equal(Rational.__send__(:new, 2**32,2**32), c)
+    assert_equal([1,1], [c.numerator,c.denominator])
+
+    c = Rational(-2**32, 2**32)
+    assert_equal(Rational.__send__(:new, -2**32,2**32), c)
+    assert_equal([-1,1], [c.numerator,c.denominator])
+
+    c = Rational(2**32, -2**32)
+    assert_equal(Rational.__send__(:new, 2**32,-2**32), c)
+    assert_equal([-1,1], [c.numerator,c.denominator])
+
+    c = Rational(-2**32, -2**32)
+    assert_equal(Rational.__send__(:new, -2**32,-2**32), c)
+    assert_equal([1,1], [c.numerator,c.denominator])
+
+    c = Rational(Rational(1,2),2)
+    assert_equal(Rational.__send__(:new, 1,4), c)
+
+    c = Rational(2,Rational(1,2))
+    assert_equal(Rational.__send__(:new, 4), c)
+
+    c = Rational(Rational(1,2),Rational(1,2))
+    assert_equal(Rational.__send__(:new, 1), c)
+
+    assert_equal(Rational.__send__(:new, 1),Rational(1))
+    assert_equal(1.1.to_r,Rational(1.1))
+    assert_equal(Rational.__send__(:new, 1),Rational('1'))
+    assert_raise(ArgumentError){Rational(nil)}
+  end
+
+  def test_attr
+    c = Rational(4)
+
+    assert_equal(4, c.numerator)
+    assert_equal(1, c.denominator)
+
+    c = Rational(4,5)
+
+    assert_equal(4, c.numerator)
+    assert_equal(5, c.denominator)
+
+    c = Rational.__send__(:new, 4)
+
+    assert_equal(4, c.numerator)
+    assert_equal(1, c.denominator)
+
+    c = Rational.__send__(:new, 4,5)
+
+    assert_equal(4, c.numerator)
+    assert_equal(5, c.denominator)
+
+    c = Rational.__send__(:new!, 4)
+
+    assert_equal(4, c.numerator)
+    assert_equal(1, c.denominator)
+
+    c = Rational.__send__(:new!, 4,5)
+
+    assert_equal(4, c.numerator)
+    assert_equal(5, c.denominator)
+  end
+
+  def test_attr2
+    c = Rational(1)
+
+    if defined?(Rational::Unify)
+      assert_equal(true, c.scalar?)
+=begin
+      assert_equal(true, c.finite?)
+      assert_equal(false, c.infinite?)
+      assert_equal(false, c.nan?)
+      assert_equal(true, c.integer?)
+      assert_equal(false, c.float?)
+      assert_equal(true, c.rational?)
+      assert_equal(true, c.real?)
+      assert_equal(false, c.complex?)
+      assert_equal(true, c.exact?)
+      assert_equal(false, c.inexact?)
+=end
+    else
+      assert_equal(true, c.scalar?)
+=begin
+      assert_equal(true, c.finite?)
+      assert_equal(false, c.infinite?)
+      assert_equal(false, c.nan?)
+      assert_equal(false, c.integer?)
+      assert_equal(false, c.float?)
+      assert_equal(true, c.rational?)
+      assert_equal(true, c.real?)
+      assert_equal(false, c.complex?)
+      assert_equal(true, c.exact?)
+      assert_equal(false, c.inexact?)
+=end
+    end
+
+=begin
+    assert_equal(true, Rational(0).positive?)
+    assert_equal(true, Rational(1).positive?)
+    assert_equal(false, Rational(-1).positive?)
+    assert_equal(false, Rational(0).negative?)
+    assert_equal(false, Rational(1).negative?)
+    assert_equal(true, Rational(-1).negative?)
+
+    assert_equal(0, Rational(0).sign)
+    assert_equal(1, Rational(2).sign)
+    assert_equal(-1, Rational(-2).sign)
+=end
+
+    assert_equal(true, Rational(0).zero?)
+    assert_equal(true, Rational(0,1).zero?)
+    assert_equal(false, Rational(1,1).zero?)
+
+    assert_equal(nil, Rational(0).nonzero?)
+    assert_equal(nil, Rational(0,1).nonzero?)
+    assert_equal(Rational(1,1), Rational(1,1).nonzero?)
+  end
+
+  def test_uplus
+    assert_equal(Rational(1), +Rational(1))
+    assert_equal(Rational(-1), +Rational(-1))
+    assert_equal(Rational(1,1), +Rational(1,1))
+    assert_equal(Rational(-1,1), +Rational(-1,1))
+    assert_equal(Rational(-1,1), +Rational(1,-1))
+    assert_equal(Rational(1,1), +Rational(-1,-1))
+  end
+
+  def test_negate
+    assert_equal(Rational(-1), -Rational(1))
+    assert_equal(Rational(1), -Rational(-1))
+    assert_equal(Rational(-1,1), -Rational(1,1))
+    assert_equal(Rational(1,1), -Rational(-1,1))
+    assert_equal(Rational(1,1), -Rational(1,-1))
+    assert_equal(Rational(-1,1), -Rational(-1,-1))
+
+=begin
+    assert_equal(0, Rational(0).negate)
+    assert_equal(-2, Rational(2).negate)
+    assert_equal(2, Rational(-2).negate)
+=end
+  end
+
+  def test_add
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    assert_equal(Rational(7,6), c + c2)
+
+    assert_equal(Rational(5,2), c + 2)
+    assert_equal(2.5, c + 2.0)
+  end
+
+  def test_sub
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    assert_equal(Rational(-1,6), c - c2)
+
+    assert_equal(Rational(-3,2), c - 2)
+    assert_equal(-1.5, c - 2.0)
+  end
+
+  def test_mul
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    assert_equal(Rational(1,3), c * c2)
+
+    assert_equal(Rational(1,1), c * 2)
+    assert_equal(1.0, c * 2.0)
+  end
+
+  def test_div
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    assert_equal(Rational(3,4), c / c2)
+
+    assert_equal(Rational(1,4), c / 2)
+    assert_equal(0.25, c / 2.0)
+  end
+
+  def assert_eql(exp, act, *args)
+    unless Array === exp
+      exp = [exp]
+    end
+    unless Array === act
+      act = [act]
+    end
+    exp.zip(act).each do |e, a|
+      na = [e, a] + args
+      assert_equal(*na)
+      na = [e.class, a] + args
+      assert_instance_of(*na)
+    end
+  end
+
+  def test_idiv
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    assert_eql(0, c.div(c2))
+    assert_eql(0, c.div(2))
+    assert_eql(0, c.div(2.0))
+
+    c = Rational(301,100)
+    c2 = Rational(7,5)
+
+    assert_equal(2, c.div(c2))
+    assert_equal(-3, c.div(-c2))
+    assert_equal(-3, (-c).div(c2))
+    assert_equal(2, (-c).div(-c2))
+
+    c = Rational(301,100)
+    c2 = Rational(2)
+
+    assert_equal(1, c.div(c2))
+    assert_equal(-2, c.div(-c2))
+    assert_equal(-2, (-c).div(c2))
+    assert_equal(1, (-c).div(-c2))
+
+    unless defined?(Rational::Unify)
+      c = Rational(11)
+      c2 = Rational(3)
+
+      assert_equal(3, c.div(c2))
+      assert_equal(-4, c.div(-c2))
+      assert_equal(-4, (-c).div(c2))
+      assert_equal(3, (-c).div(-c2))
+    end
+  end
+
+  def test_divmod
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    assert_eql([0, Rational(1,2)], c.divmod(c2))
+    assert_eql([0, Rational(1,2)], c.divmod(2))
+    assert_eql([0, 0.5], c.divmod(2.0))
+
+    c = Rational(301,100)
+    c2 = Rational(7,5)
+
+    assert_equal([2, Rational(21,100)], c.divmod(c2))
+    assert_equal([-3, Rational(-119,100)], c.divmod(-c2))
+    assert_equal([-3, Rational(119,100)], (-c).divmod(c2))
+    assert_equal([2, Rational(-21,100)], (-c).divmod(-c2))
+
+    c = Rational(301,100)
+    c2 = Rational(2)
+
+    assert_equal([1, Rational(101,100)], c.divmod(c2))
+    assert_equal([-2, Rational(-99,100)], c.divmod(-c2))
+    assert_equal([-2, Rational(99,100)], (-c).divmod(c2))
+    assert_equal([1, Rational(-101,100)], (-c).divmod(-c2))
+
+    unless defined?(Rational::Unify)
+      c = Rational(11)
+      c2 = Rational(3)
+
+      assert_equal([3,2], c.divmod(c2))
+      assert_equal([-4,-1], c.divmod(-c2))
+      assert_equal([-4,1], (-c).divmod(c2))
+      assert_equal([3,-2], (-c).divmod(-c2))
+    end
+  end
+
+=begin
+  def test_quot
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    assert_eql(0, c.quot(c2))
+    assert_eql(0, c.quot(2))
+    assert_eql(0, c.quot(2.0))
+
+    c = Rational(301,100)
+    c2 = Rational(7,5)
+
+    assert_equal(2, c.quot(c2))
+    assert_equal(-2, c.quot(-c2))
+    assert_equal(-2, (-c).quot(c2))
+    assert_equal(2, (-c).quot(-c2))
+
+    c = Rational(301,100)
+    c2 = Rational(2)
+
+    assert_equal(1, c.quot(c2))
+    assert_equal(-1, c.quot(-c2))
+    assert_equal(-1, (-c).quot(c2))
+    assert_equal(1, (-c).quot(-c2))
+
+    unless defined?(Rational::Unify)
+      c = Rational(11)
+      c2 = Rational(3)
+
+      assert_equal(3, c.quot(c2))
+      assert_equal(-3, c.quot(-c2))
+      assert_equal(-3, (-c).quot(c2))
+      assert_equal(3, (-c).quot(-c2))
+    end
+  end
+
+  def test_quotrem
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    assert_eql([0, Rational(1,2)], c.quotrem(c2))
+    assert_eql([0, Rational(1,2)], c.quotrem(2))
+    assert_eql([0, 0.5], c.quotrem(2.0))
+
+    c = Rational(301,100)
+    c2 = Rational(7,5)
+
+    assert_equal([2, Rational(21,100)], c.quotrem(c2))
+    assert_equal([-2, Rational(21,100)], c.quotrem(-c2))
+    assert_equal([-2, Rational(-21,100)], (-c).quotrem(c2))
+    assert_equal([2, Rational(-21,100)], (-c).quotrem(-c2))
+
+    c = Rational(301,100)
+    c2 = Rational(2)
+
+    assert_equal([1, Rational(101,100)], c.quotrem(c2))
+    assert_equal([-1, Rational(101,100)], c.quotrem(-c2))
+    assert_equal([-1, Rational(-101,100)], (-c).quotrem(c2))
+    assert_equal([1, Rational(-101,100)], (-c).quotrem(-c2))
+
+    unless defined?(Rational::Unify)
+      c = Rational(11)
+      c2 = Rational(3)
+
+      assert_equal([3,2], c.quotrem(c2))
+      assert_equal([-3,2], c.quotrem(-c2))
+      assert_equal([-3,-2], (-c).quotrem(c2))
+      assert_equal([3,-2], (-c).quotrem(-c2))
+    end
+  end
+=end
+
+  def test_quo
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    assert_equal(Rational(3,4), c.quo(c2))
+
+    assert_equal(Rational(1,4), c.quo(2))
+    assert_equal(Rational(0.25), c.quo(2.0))
+  end
+
+  def test_rdiv
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    assert_equal(Rational(3,4), c.rdiv(c2))
+
+    assert_equal(Rational(1,4), c.rdiv(2))
+    assert_equal(Rational(0.25), c.rdiv(2.0))
+  end
+
+  def test_fdiv
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    assert_equal(0.75, c.fdiv(c2))
+
+    assert_equal(0.25, c.fdiv(2))
+    assert_equal(0.25, c.fdiv(2.0))
+  end
+
+  def test_expt
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    r = c ** c2
+    assert_in_delta(0.6299, r, 0.001)
+
+    assert_equal(Rational(1,4), c ** 2)
+    assert_equal(Rational(4), c ** -2)
+    assert_equal(Rational(1,4), (-c) ** 2)
+    assert_equal(Rational(4), (-c) ** -2)
+
+    assert_equal(0.25, c ** 2.0)
+    assert_equal(4.0, c ** -2.0)
+
+    assert_equal(Rational(1,4), c ** Rational(2))
+    assert_equal(Rational(4), c ** Rational(-2))
+
+    assert_equal(Rational(1), 0 ** Rational(0))
+    assert_equal(Rational(1), Rational(0) ** 0)
+    assert_equal(Rational(1), Rational(0) ** Rational(0))
+
+    # p ** p
+    x = 2 ** Rational(2)
+    assert_equal(Rational(4), x)
+    unless defined?(Rational::Unify)
+      assert_instance_of(Rational, x)
+    end
+    assert_equal(4, x.numerator)
+    assert_equal(1, x.denominator)
+
+    x = Rational(2) ** 2
+    assert_equal(Rational(4), x)
+    unless defined?(Rational::Unify)
+      assert_instance_of(Rational, x)
+    end
+    assert_equal(4, x.numerator)
+    assert_equal(1, x.denominator)
+
+    x = Rational(2) ** Rational(2)
+    assert_equal(Rational(4), x)
+    unless defined?(Rational::Unify)
+      assert_instance_of(Rational, x)
+    end
+    assert_equal(4, x.numerator)
+    assert_equal(1, x.denominator)
+
+    # -p ** p
+    x = (-2) ** Rational(2)
+    assert_equal(Rational(4), x)
+    unless defined?(Rational::Unify)
+      assert_instance_of(Rational, x)
+    end
+    assert_equal(4, x.numerator)
+    assert_equal(1, x.denominator)
+
+    x = Rational(-2) ** 2
+    assert_equal(Rational(4), x)
+    unless defined?(Rational::Unify)
+      assert_instance_of(Rational, x)
+    end
+    assert_equal(4, x.numerator)
+    assert_equal(1, x.denominator)
+
+    x = Rational(-2) ** Rational(2)
+    assert_equal(Rational(4), x)
+    unless defined?(Rational::Unify)
+      assert_instance_of(Rational, x)
+    end
+    assert_equal(4, x.numerator)
+    assert_equal(1, x.denominator)
+
+    # p ** -p
+    x = 2 ** Rational(-2)
+    assert_equal(Rational(1,4), x)
+    assert_instance_of(Rational, x)
+    assert_equal(1, x.numerator)
+    assert_equal(4, x.denominator)
+
+    x = Rational(2) ** -2
+    assert_equal(Rational(1,4), x)
+    assert_instance_of(Rational, x)
+    assert_equal(1, x.numerator)
+    assert_equal(4, x.denominator)
+
+    x = Rational(2) ** Rational(-2)
+    assert_equal(Rational(1,4), x)
+    assert_instance_of(Rational, x)
+    assert_equal(1, x.numerator)
+    assert_equal(4, x.denominator)
+
+    # -p ** -p
+    x = (-2) ** Rational(-2)
+    assert_equal(Rational(1,4), x)
+    assert_instance_of(Rational, x)
+    assert_equal(1, x.numerator)
+    assert_equal(4, x.denominator)
+
+    x = Rational(-2) ** -2
+    assert_equal(Rational(1,4), x)
+    assert_instance_of(Rational, x)
+    assert_equal(1, x.numerator)
+    assert_equal(4, x.denominator)
+
+    x = Rational(-2) ** Rational(-2)
+    assert_equal(Rational(1,4), x)
+    assert_instance_of(Rational, x)
+    assert_equal(1, x.numerator)
+    assert_equal(4, x.denominator)
+  end
+
+  def test_cmp
+    assert_equal(-1, Rational(-1) <=> Rational(0))
+    assert_equal(0, Rational(0) <=> Rational(0))
+    assert_equal(+1, Rational(+1) <=> Rational(0))
+
+    assert_equal(-1, Rational(-1) <=> 0)
+    assert_equal(0, Rational(0) <=> 0)
+    assert_equal(+1, Rational(+1) <=> 0)
+
+    assert_equal(-1, Rational(-1) <=> 0.0)
+    assert_equal(0, Rational(0) <=> 0.0)
+    assert_equal(+1, Rational(+1) <=> 0.0)
+
+    assert_equal(-1, Rational(1,2) <=> Rational(2,3))
+    assert_equal(0, Rational(2,3) <=> Rational(2,3))
+    assert_equal(+1, Rational(2,3) <=> Rational(1,2))
+
+    f = 2**30-1
+    b = 2**30
+
+    assert_equal(0, Rational(f) <=> Rational(f))
+    assert_equal(-1, Rational(f) <=> Rational(b))
+    assert_equal(+1, Rational(b) <=> Rational(f))
+    assert_equal(0, Rational(b) <=> Rational(b))
+
+    assert_equal(-1, Rational(f-1) <=> Rational(f))
+    assert_equal(+1, Rational(f) <=> Rational(f-1))
+    assert_equal(-1, Rational(b-1) <=> Rational(b))
+    assert_equal(+1, Rational(b) <=> Rational(b-1))
+
+    assert_equal(false, Rational(0) < Rational(0))
+    assert_equal(true, Rational(0) <= Rational(0))
+    assert_equal(true, Rational(0) >= Rational(0))
+    assert_equal(false, Rational(0) > Rational(0))
+  end
+
+  def test_equal
+    assert(Rational(1,1) == Rational(1))
+    assert(Rational(1,1) == Rational.__send__(:new, 1))
+    assert(Rational(1,1) == Rational.__send__(:new, 1,1))
+    assert(Rational(1,1) == Rational.__send__(:new!, 1))
+    assert(Rational(1,1) == Rational.__send__(:new!, 1,1))
+
+    assert(Rational(-1,1) == Rational(-1))
+    assert(Rational(-1,1) == Rational.__send__(:new, -1))
+    assert(Rational(-1,1) == Rational.__send__(:new, -1,1))
+    assert(Rational(-1,1) == Rational.__send__(:new!, -1))
+    assert(Rational(-1,1) == Rational.__send__(:new!, -1,1))
+
+    assert_equal(false, Rational(2,1) == Rational(1))
+    assert_equal(true, Rational(2,1) != Rational(1))
+    assert_equal(false, Rational(1) == nil)
+    assert_equal(false, Rational(1) == '')
+  end
+
+  def test_unify
+    if defined?(Rational::Unify)
+      assert_instance_of(Fixnum, Rational(1,2) + Rational(1,2))
+      assert_instance_of(Fixnum, Rational(1,2) - Rational(1,2))
+      assert_instance_of(Fixnum, Rational(1,2) * 2)
+      assert_instance_of(Fixnum, Rational(1,2) / Rational(1,2))
+      assert_instance_of(Fixnum, Rational(1,2).div(Rational(1,2)))
+      assert_instance_of(Fixnum, Rational(1,2).quo(Rational(1,2)))
+      assert_instance_of(Fixnum, Rational(1,2) ** -2)
+    end
+  end
+
+  def test_to_s
+    c = Rational(1,2)
+
+    assert_instance_of(String, c.to_s)
+    assert_equal('1/2', c.to_s)
+
+    assert_equal('0', Rational(0,2).to_s)
+    assert_equal('0', Rational(0,-2).to_s)
+    assert_equal('1/2', Rational(1,2).to_s)
+    assert_equal('-1/2', Rational(-1,2).to_s)
+    assert_equal('1/2', Rational(-1,-2).to_s)
+    assert_equal('-1/2', Rational(1,-2).to_s)
+    assert_equal('1/2', Rational(-1,-2).to_s)
+  end
+
+  def test_inspect
+    c = Rational(1,2)
+
+    assert_instance_of(String, c.inspect)
+    assert_equal('Rational(1, 2)', c.inspect)
+  end
+
+  def test_marshal
+    c = Rational(1,2)
+
+    s = Marshal.dump(c)
+    c2 = Marshal.load(s)
+    assert_equal(c, c2)
+    assert_instance_of(Rational, c2)
+  end
+
+  def test_parse
+    assert_equal(Rational(0), ''.to_r)
+    assert_equal(Rational(0), ' '.to_r)
+    assert_equal(Rational(5), '5'.to_r)
+    assert_equal(Rational(-5), '-5'.to_r)
+    assert_equal(Rational(5,3), '5/3'.to_r)
+    assert_equal(Rational(-5,3), '-5/3'.to_r)
+    assert_equal(Rational(5,-3), '5/-3'.to_r)
+    assert_equal(Rational(-5,-3), '-5/-3'.to_r)
+
+    assert_equal(Rational(5), '5.0'.to_r)
+    assert_equal(Rational(-5), '-5.0'.to_r)
+    assert_equal(Rational(5,3), '5.0/3'.to_r)
+    assert_equal(Rational(-5,3), '-5.0/3'.to_r)
+    assert_equal(Rational(5,-3), '5.0/-3'.to_r)
+    assert_equal(Rational(-5,-3), '-5.0/-3'.to_r)
+
+    assert_equal(Rational(5), '5e0'.to_r)
+    assert_equal(Rational(-5), '-5e0'.to_r)
+    assert_equal(Rational(5,3), '5e0/3'.to_r)
+    assert_equal(Rational(-5,3), '-5e0/3'.to_r)
+    assert_equal(Rational(5,-3), '5e0/-3'.to_r)
+    assert_equal(Rational(-5,-3), '-5e0/-3'.to_r)
+
+    assert_equal(Rational(33,100), '0.33'.to_r)
+    assert_equal(Rational(-33,100), '-0.33'.to_r)
+    assert_equal(Rational(-33,100), '-0.3_3'.to_r)
+
+    assert_equal(Rational(1,2), '5e-1'.to_r)
+    assert_equal(Rational(50), '5e+1'.to_r)
+    assert_equal(Rational(1,2), '5.0e-1'.to_r)
+    assert_equal(Rational(50), '5.0e+1'.to_r)
+    assert_equal(Rational(50), '5e1'.to_r)
+    assert_equal(Rational(50), '5E1'.to_r)
+    assert_equal(Rational(500), '5e2'.to_r)
+    assert_equal(Rational(5000), '5e3'.to_r)
+    assert_equal(Rational(500000000000), '5e1_1'.to_r)
+
+    assert_equal(Rational(5), Rational('5'))
+    assert_equal(Rational(-5), Rational('-5'))
+    assert_equal(Rational(5,3), Rational('5/3'))
+    assert_equal(Rational(-5,3), Rational('-5/3'))
+    assert_equal(Rational(5,-3), Rational('5/-3'))
+    assert_equal(Rational(-5,-3), Rational('-5/-3'))
+
+    assert_equal(Rational(33,100), Rational('0.33'))
+    assert_equal(Rational(-33,100), Rational('-0.33'))
+    assert_equal(Rational(-33,100), Rational('-0.3_3'))
+
+    assert_equal(Rational(1,2), Rational('5e-1'))
+    assert_equal(Rational(50), Rational('5e1'))
+    assert_equal(Rational(50), Rational('5E1'))
+    assert_equal(Rational(500), Rational('5e2'))
+    assert_equal(Rational(5000), Rational('5e3'))
+    assert_equal(Rational(500000000000), Rational('5e1_1'))
+
+    assert_equal(Rational(5.0), Rational('5.0'))
+    assert_equal(Rational(-5.0), Rational('-5.0'))
+    assert_equal(Rational(5.0,3), Rational('5.0/3'))
+    assert_equal(Rational(-5.0,3), Rational('-5.0/3'))
+    assert_equal(Rational(5.0,-3), Rational('5.0/-3'))
+    assert_equal(Rational(-5.0,-3), Rational('-5.0/-3'))
+
+    assert_equal(Rational(0), '_'.to_r)
+    assert_equal(Rational(0), '_5'.to_r)
+    assert_equal(Rational(5), '5_'.to_r)
+    assert_equal(Rational(5), '5x'.to_r)
+    assert_equal(Rational(5), '5/_3'.to_r)
+    assert_equal(Rational(5,3), '5/3_'.to_r)
+    assert_equal(Rational(5,3), '5/3.3'.to_r)
+    assert_equal(Rational(5,3), '5/3x'.to_r)
+    assert_raise(ArgumentError){ Rational('')}
+    assert_raise(ArgumentError){ Rational('_')}
+    assert_raise(ArgumentError){ Rational('_5')}
+    assert_raise(ArgumentError){ Rational('5_')}
+    assert_raise(ArgumentError){ Rational('5x')}
+    assert_raise(ArgumentError){ Rational('5/_3')}
+    assert_raise(ArgumentError){ Rational('5/3_')}
+    assert_raise(ArgumentError){ Rational('5/3.3')}
+    assert_raise(ArgumentError){ Rational('5/3x')}
+  end
+
+=begin
+  def test_reciprocal
+    assert_equal(Rational(1,9), Rational(9,1).reciprocal)
+    assert_equal(Rational(9,1), Rational(1,9).reciprocal)
+    assert_equal(Rational(-1,9), Rational(-9,1).reciprocal)
+    assert_equal(Rational(-9,1), Rational(-1,9).reciprocal)
+  end
+=end
+
+  def test_to_i
+    assert_equal(1, Rational(3,2).to_i)
+    assert_equal(1, Integer(Rational(3,2)))
+  end
+
+  def test_to_f
+    assert_equal(1.5, Rational(3,2).to_f)
+    assert_equal(1.5, Float(Rational(3,2)))
+  end
+
+  def test_to_c
+    if defined?(Complex) && !Complex.instance_variable_get('@RCS_ID')
+      if defined?(Rational::Unify)
+	assert_equal(Rational(3,2), Rational(3,2).to_c)
+	assert_equal(Rational(3,2), Complex(Rational(3,2)))
+      else
+	assert_equal(Complex(Rational(3,2)), Rational(3,2).to_c)
+	assert_equal(Complex(Rational(3,2)), Complex(Rational(3,2)))
+      end
+    end
+  end
+
+  def test_to_r
+    c = nil.to_r
+    assert_equal([0,1] , [c.numerator, c.denominator])
+
+    c = 0.to_r
+    assert_equal([0,1] , [c.numerator, c.denominator])
+
+    c = 1.to_r
+    assert_equal([1,1] , [c.numerator, c.denominator])
+
+    c = 1.1.to_r
+    assert_equal([2476979795053773, 2251799813685248],
+		 [c.numerator, c.denominator])
+
+    c = Rational(1,2).to_r
+    assert_equal([1,2] , [c.numerator, c.denominator])
+
+    if defined?(Complex)
+      if Complex.instance_variable_get('@RCS_ID')
+	assert_raise(NoMethodError){Complex(1,2).to_r}
+      else
+	assert_raise(RangeError){Complex(1,2).to_r}
+      end
+    end
+  end
+
+  def test_prec
+    assert_equal(true, Rational < Precision)
+
+    c = Rational(3,2)
+
+    assert_eql(1, c.prec(Integer))
+    assert_eql(1.5, c.prec(Float))
+    assert_eql(c, c.prec(Rational))
+  end
+
+  def test_supp
+    assert_equal(true, 1.scalar?)
+    assert_equal(true, 1.1.scalar?)
+
+    if defined?(Complex)
+      assert_equal(1, 1.real)
+      assert_equal(0, 1.image)
+      assert_equal(0, 1.imag)
+
+      assert_equal(1.1, 1.1.real)
+      assert_equal(0, 1.1.image)
+      assert_equal(0, 1.1.imag)
+
+      assert_equal(0, 1.arg)
+      assert_equal(0, 1.angle)
+
+      assert_equal(0, 1.0.arg)
+      assert_equal(0, 1.0.angle)
+
+      assert_equal(Math::PI, -1.arg)
+      assert_equal(Math::PI, -1.angle)
+
+      assert_equal(Math::PI, -1.0.arg)
+      assert_equal(Math::PI, -1.0.angle)
+
+      assert_equal([1,0], 1.polar)
+      assert_equal([1, Math::PI], -1.polar)
+
+      assert_equal([1.0,0], 1.0.polar)
+      assert_equal([1.0, Math::PI], -1.0.polar)
+
+      assert_equal(1, 1.conjugate)
+      assert_equal(-1, -1.conjugate)
+      assert_equal(1, 1.conj)
+      assert_equal(-1, -1.conj)
+
+      assert_equal(1.1, 1.1.conjugate)
+      assert_equal(-1.1, -1.1.conjugate)
+      assert_equal(1.1, 1.1.conj)
+      assert_equal(-1.1, -1.1.conj)
+    end
+
+    assert_equal(1, 1.numerator)
+    assert_equal(9, 9.numerator)
+    assert_equal(1, 1.denominator)
+    assert_equal(1, 9.denominator)
+
+    assert_equal(1.0, 1.0.numerator)
+    assert_equal(9.0, 9.0.numerator)
+    assert_equal(1.0, 1.0.denominator)
+    assert_equal(1.0, 9.0.denominator)
+
+=begin
+    assert_equal(Rational(1,9), 9.reciprocal)
+    assert_equal(Rational(1,9), 9.0.reciprocal)
+    assert_equal(Rational(1,9), 9.inverse)
+    assert_equal(Rational(1,9), 9.0.inverse)
+=end
+
+    assert_equal(Rational(1,2), 1.quo(2))
+    assert_equal(Rational(5000000000), 10000000000.quo(2))
+    assert_equal(0.5, 1.0.quo(2))
+    assert_equal(Rational(1,4), Rational(1,2).quo(2))
+
+    assert_equal(Rational(1,2), 1.rdiv(2))
+    assert_equal(Rational(5000000000), 10000000000.rdiv(2))
+    assert_equal(Rational(1,2), 1.0.rdiv(2))
+    assert_equal(Rational(1,4), Rational(1,2).rdiv(2))
+
+    assert_equal(0.5, 1.fdiv(2))
+    assert_equal(5000000000.0, 10000000000.fdiv(2))
+    assert_equal(0.5, 1.0.fdiv(2))
+    assert_equal(0.25, Rational(1,2).fdiv(2))
+  end
+
+  def test_fixed_bug
+    if defined?(Rational::Unify)
+      assert_instance_of(Fixnum, Rational(1,2) ** 0) # mathn's bug
+    end
+  end
+
+=begin
+  def test_known_bug
+    n = Float::MAX.to_i * 2
+    assert_equal(1.0, Rational(n + 2, n + 1).to_f, '[ruby-dev:33852]')
+  end
+=end
+
+end

Property changes on: test/ruby/test_rational.rb
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Index: rational.c
===================================================================
--- rational.c	(revision 0)
+++ rational.c	(revision 15783)
@@ -0,0 +1,1111 @@
+/*
+  nurat_core.c: Coded by Tadayoshi Funaba 2008
+
+  This implementation is based on Keiju Ishitsuka's Rational library
+  which is written in ruby.
+*/
+
+#include "ruby.h"
+#include <math.h>
+
+#define NDEBUG
+#include <assert.h>
+
+#ifndef RATIONAL_NAME
+#define RATIONAL_NAME "Rational"
+#endif
+
+#define ZERO INT2FIX(0)
+#define ONE INT2FIX(1)
+#define TWO INT2FIX(2)
+
+VALUE rb_cRational;
+
+static ID id_Unify, id_cmp, id_coerce, 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;
+
+#define f_add(x,y) rb_funcall(x, '+', 1, y)
+#define f_div(x,y) rb_funcall(x, '/', 1, y)
+#define f_gt_p(x,y) rb_funcall(x, '>', 1, y)
+#define f_lt_p(x,y) rb_funcall(x, '<', 1, y)
+#define f_mod(x,y) rb_funcall(x, '%', 1, y)
+#define f_mul(x,y) rb_funcall(x, '*', 1, y)
+#define f_sub(x,y) rb_funcall(x, '-', 1, y)
+#define f_xor(x,y) rb_funcall(x, '^', 1, y)
+
+#define f_floor(x) rb_funcall(x, id_floor, 0)
+#define f_inspect(x) rb_funcall(x, id_inspect, 0)
+#define f_to_f(x) rb_funcall(x, id_to_f, 0)
+#define f_to_i(x) rb_funcall(x, id_to_i, 0)
+#define f_to_s(x) rb_funcall(x, id_to_s, 0)
+#define f_truncate(x) rb_funcall(x, id_truncate, 0)
+#define f_cmp(x,y) rb_funcall(x, id_cmp, 1, y)
+#define f_coerce(x,y) rb_funcall(x, id_coerce, 1, y)
+#define f_equal_p(x,y) rb_funcall(x, id_equal_p, 1, y)
+#define f_expt(x,y) rb_funcall(x, id_expt, 1, y)
+#define f_idiv(x,y) rb_funcall(x, id_idiv, 1, y)
+#define f_negate(x) rb_funcall(x, id_negate, 0)
+
+#define f_negative_p(x) f_lt_p(x, ZERO)
+#define f_zero_p(x) f_equal_p(x, ZERO)
+#define f_one_p(x) f_equal_p(x, ONE)
+#define f_kind_of_p(x,c) rb_obj_is_kind_of(x, c)
+#define k_numeric_p(x) f_kind_of_p(x, rb_cNumeric)
+#define k_integer_p(x) f_kind_of_p(x, rb_cInteger)
+#define k_float_p(x) f_kind_of_p(x, rb_cFloat)
+#define k_rational_p(x) f_kind_of_p(x, rb_cRational)
+
+#define f_boolcast(x) ((x) ? Qtrue : Qfalse)
+
+inline static long
+i_gcd(long x, long y)
+{
+  long b;
+
+  if (x < 0)
+    x = -x;
+  if (y < 0)
+    y = -y;
+
+  if (x == 0)
+    return y;
+  if (y == 0)
+    return x;
+
+  b = 0;
+  while ((x & 1) == 0 && (y & 1) == 0) {
+    b += 1;
+    x >>= 1;
+    y >>= 1;
+  }
+
+  while ((x & 1) == 0)
+    x >>= 1;
+
+  while ((y & 1) == 0)
+    y >>= 1;
+
+  while (x != y) {
+    if (y > x) {
+      long t;
+      t = x;
+      x = y;
+      y = t;
+    }
+    x -= y;
+    while ((x & 1) == 0)
+      x >>= 1;
+  }
+
+  return x << b;
+}
+
+inline static VALUE
+f_gcd(VALUE x, VALUE y)
+{
+  VALUE z;
+
+  if (FIXNUM_P(x) && FIXNUM_P(y))
+    return LONG2NUM(i_gcd(FIX2LONG(x), FIX2LONG(y)));
+
+  if (f_negative_p(x))
+    x = f_negate(x);
+  if (f_negative_p(y))
+    y = f_negate(y);
+
+  if (f_zero_p(x))
+    return y;
+  if (f_zero_p(y))
+    return x;
+
+  for (;;) {
+    if (FIXNUM_P(x)) {
+      if (FIX2INT(x) == 0)
+	return y;
+      if (FIXNUM_P(y))
+	return LONG2NUM(i_gcd(FIX2LONG(x), FIX2LONG(y)));
+    }
+    z = x;
+    x = f_mod(y, x);
+    y = z;
+  }
+  /* NOTREACHED */
+}
+
+#define get_dat1(x) \
+  struct RRational *dat;\
+  dat = ((struct RRational *)(x))
+
+#define get_dat2(x,y) \
+  struct RRational *adat, *bdat;\
+  adat = ((struct RRational *)(x));\
+  bdat = ((struct RRational *)(y))
+
+inline static VALUE
+nurat_s_new_internal(VALUE klass, VALUE num, VALUE den)
+{
+  NEWOBJ(obj, struct RRational);
+  OBJSETUP(obj, klass, T_RATIONAL);
+
+  obj->num = num;
+  obj->den = den;
+
+  return (VALUE)obj;
+}
+
+static VALUE
+nurat_s_alloc(VALUE klass)
+{
+  return nurat_s_new_internal(klass, ZERO, ONE);
+}
+
+static VALUE
+nurat_s_new_bang(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE num, den;
+
+  switch (rb_scan_args(argc, argv, "11", &num, &den)) {
+  case 1:
+    if (!k_integer_p(num))
+      num = f_to_i(num);
+    den = ONE;
+    break;
+  default:
+    if (!k_integer_p(num))
+      num = f_to_i(num);
+    if (!k_integer_p(den))
+      den = f_to_i(den);
+
+    if (f_negative_p(den)) {
+      num = f_negate(num);
+      den = f_negate(den);
+    }
+    break;
+  }
+
+  return nurat_s_new_internal(klass, num, den);
+}
+
+inline static VALUE
+f_rational_new_bang1(VALUE klass, VALUE x)
+{
+  return nurat_s_new_internal(klass, x, ONE);
+}
+
+inline static VALUE
+f_rational_new_bang2(VALUE klass, VALUE x, VALUE y)
+{
+  assert(!f_negative_p(y));
+  assert(!f_zero_p(y));
+  return nurat_s_new_internal(klass, x, y);
+}
+
+#define f_unify_p(klass) rb_const_defined(klass, id_Unify)
+
+inline static VALUE
+nurat_s_canonicalize_internal(VALUE klass, VALUE num, VALUE den)
+{
+  VALUE gcd;
+
+  switch (FIX2INT(f_cmp(den, ZERO))) {
+  case -1:
+    if (f_negative_p(den)) {
+      num = f_negate(num);
+      den = f_negate(den);
+    }
+    break;
+  case 0:
+    rb_raise(rb_eZeroDivError, "devided by zero");
+    break;
+  }
+
+  gcd = f_gcd(num, den);
+  num = f_idiv(num, gcd);
+  den = f_idiv(den, gcd);
+
+  if (f_one_p(den) && f_unify_p(klass))
+    return num;
+  else
+    return nurat_s_new_internal(klass, num, den);
+}
+
+static VALUE
+nurat_s_canonicalize(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE num, den;
+
+  switch (rb_scan_args(argc, argv, "11", &num, &den)) {
+  case 1:
+    den = ONE;
+    break;
+  }
+
+  switch (TYPE(num)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+    break;
+  default:
+    rb_raise(rb_eArgError, "not an integer");
+  }
+
+  switch (TYPE(den)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+    break;
+  default:
+    rb_raise(rb_eArgError, "not an integer");
+  }
+
+  return nurat_s_canonicalize_internal(klass, num, den);
+}
+
+static VALUE
+nurat_s_new(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE num, den;
+
+  switch (rb_scan_args(argc, argv, "11", &num, &den)) {
+  case 1:
+    den = ONE;
+    break;
+  }
+
+  switch (TYPE(num)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+    break;
+  default:
+    rb_raise(rb_eArgError, "not an integer");
+  }
+
+  switch (TYPE(den)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+    break;
+  default:
+    rb_raise(rb_eArgError, "not an integer");
+  }
+
+  return nurat_s_canonicalize_internal(klass, num, den);
+}
+
+inline static VALUE
+f_rational_new1(VALUE klass, VALUE x)
+{
+  assert(!k_rational_p(x));
+  return nurat_s_canonicalize_internal(klass, x, ONE);
+}
+
+inline static VALUE
+f_rational_new2(VALUE klass, VALUE x, VALUE y)
+{
+  assert(!k_rational_p(x));
+  assert(!k_rational_p(y));
+  return nurat_s_canonicalize_internal(klass, x, y);
+}
+
+static VALUE
+nurat_f_rational(int argc, VALUE *argv, VALUE klass)
+{
+  return rb_funcall2(rb_cRational, id_convert, argc, argv);
+}
+
+static VALUE
+nurat_numerator(VALUE self)
+{
+  get_dat1(self);
+  return dat->num;
+}
+
+static VALUE
+nurat_denominator(VALUE self)
+{
+  get_dat1(self);
+  return dat->den;
+}
+
+static VALUE
+nurat_add(VALUE self, VALUE other)
+{
+  switch (TYPE(other)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+    return f_add(self, f_rational_new_bang1(CLASS_OF(self), other));
+  case T_FLOAT:
+    return f_add(f_to_f(self), other);
+  case T_RATIONAL:
+    {
+      VALUE num1, num2;
+
+      get_dat2(self, other);
+
+      num1 = f_mul(adat->num, bdat->den);
+      num2 = f_mul(bdat->num, adat->den);
+
+      return f_rational_new2(CLASS_OF(self),
+			     f_add(num1, num2),
+			     f_mul(adat->den, bdat->den));
+    }
+  default:
+    {
+      VALUE a = f_coerce(other, self);
+      return f_add(RARRAY_PTR(a)[0], RARRAY_PTR(a)[1]);
+    }
+  }
+}
+
+static VALUE
+nurat_sub(VALUE self, VALUE other)
+{
+  switch (TYPE(other)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+    return f_sub(self, f_rational_new_bang1(CLASS_OF(self), other));
+  case T_FLOAT:
+    return f_sub(f_to_f(self), other);
+  case T_RATIONAL:
+    {
+      VALUE num1, num2;
+
+      get_dat2(self, other);
+
+      num1 = f_mul(adat->num, bdat->den);
+      num2 = f_mul(bdat->num, adat->den);
+
+      return f_rational_new2(CLASS_OF(self),
+			     f_sub(num1, num2),
+			     f_mul(adat->den, bdat->den));
+    }
+  default:
+    {
+      VALUE a = f_coerce(other, self);
+      return f_sub(RARRAY_PTR(a)[0], RARRAY_PTR(a)[1]);
+    }
+  }
+}
+
+static VALUE
+nurat_mul(VALUE self, VALUE other)
+{
+  switch (TYPE(other)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+    return f_mul(self, f_rational_new_bang1(CLASS_OF(self), other));
+  case T_FLOAT:
+    return f_mul(f_to_f(self), other);
+  case T_RATIONAL:
+    {
+      VALUE num, den;
+
+      get_dat2(self, other);
+
+      num = f_mul(adat->num, bdat->num);
+      den = f_mul(adat->den, bdat->den);
+
+      return f_rational_new2(CLASS_OF(self), num, den);
+    }
+  default:
+    {
+      VALUE a = f_coerce(other, self);
+      return f_mul(RARRAY_PTR(a)[0], RARRAY_PTR(a)[1]);
+    }
+  }
+}
+
+static VALUE
+nurat_div(VALUE self, VALUE other)
+{
+  switch (TYPE(other)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+    if (f_zero_p(other))
+      rb_raise(rb_eZeroDivError, "devided by zero");
+    return f_div(self, f_rational_new_bang1(CLASS_OF(self), other));
+  case T_FLOAT:
+    return f_div(f_to_f(self), other);
+  case T_RATIONAL:
+    {
+      VALUE num, den;
+
+      get_dat2(self, other);
+
+      num = f_mul(adat->num, bdat->den);
+      den = f_mul(adat->den, bdat->num);
+
+      return f_rational_new2(CLASS_OF(self), num, den);
+    }
+  default:
+    {
+      VALUE a = f_coerce(other, self);
+      return f_div(RARRAY_PTR(a)[0], RARRAY_PTR(a)[1]);
+    }
+  }
+}
+
+static VALUE
+nurat_fdiv(VALUE self, VALUE other)
+{
+  return f_div(f_to_f(self), other);
+}
+
+static VALUE
+nurat_expt(VALUE self, VALUE other)
+{
+  if (f_zero_p(other))
+    return f_rational_new_bang1(CLASS_OF(self), ONE);
+
+  if (k_rational_p(other)) {
+    get_dat1(other);
+
+    if (f_one_p(dat->den))
+      other = dat->num; /* good? */
+  }
+
+  switch (TYPE(other)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+    {
+      VALUE num, den;
+
+      get_dat1(self);
+
+      switch (FIX2INT(f_cmp(other, ZERO))) {
+      case 1:
+	num = f_expt(dat->num, other);
+	den = f_expt(dat->den, other);
+	break;
+      case -1:
+	num = f_expt(dat->den, f_negate(other));
+	den = f_expt(dat->num, f_negate(other));
+	break;
+      default:
+	num = ONE;
+	den = ONE;
+	break;
+      }
+      if (f_negative_p(den)) { /* or use normal new */
+	num = f_negate(num);
+	den = f_negate(den);
+      }
+      return f_rational_new_bang2(CLASS_OF(self), num, den);
+    }
+  case T_FLOAT:
+  case T_RATIONAL:
+    return f_expt(f_to_f(self), other);
+  default:
+    {
+      VALUE a = f_coerce(other, self);
+      return f_expt(RARRAY_PTR(a)[0], RARRAY_PTR(a)[1]);
+    }
+  }
+}
+
+static VALUE
+nurat_cmp(VALUE self, VALUE other)
+{
+  switch (TYPE(other)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+    return f_cmp(self, f_rational_new_bang1(CLASS_OF(self), other));
+  case T_FLOAT:
+    return f_cmp(f_to_f(self), other);
+  case T_RATIONAL:
+    {
+      VALUE num1, num2;
+
+      get_dat2(self, other);
+
+      num1 = f_mul(adat->num, bdat->den);
+      num2 = f_mul(bdat->num, adat->den);
+      return f_cmp(f_sub(num1, num2), ZERO);
+    }
+  default:
+    {
+      VALUE a = f_coerce(other, self);
+      return f_cmp(RARRAY_PTR(a)[0], RARRAY_PTR(a)[1]);
+    }
+  }
+}
+
+static VALUE
+nurat_equal_p(VALUE self, VALUE other)
+{
+  switch (TYPE(other)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+    return f_equal_p(self, f_rational_new_bang1(CLASS_OF(self), other));
+  case T_FLOAT:
+    return f_equal_p(f_to_f(self), other);
+  case T_RATIONAL:
+    {
+      get_dat2(self, other);
+
+      return f_boolcast(f_equal_p(adat->num, bdat->num) &&
+			f_equal_p(adat->den, bdat->den));
+    }
+  default:
+    return f_equal_p(other, self);
+  }
+}
+
+static VALUE
+nurat_coerce(VALUE self, VALUE other)
+{
+  switch (TYPE(other)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+    return rb_assoc_new(f_rational_new_bang1(CLASS_OF(self), other), self);
+  case T_FLOAT:
+    return rb_assoc_new(other, f_to_f(self));
+  }
+
+  rb_raise(rb_eTypeError, "%s can't be coerced into %s",
+	   rb_obj_classname(other), rb_obj_classname(self));
+  return Qnil;
+}
+
+static VALUE
+nurat_idiv(VALUE self, VALUE other)
+{
+  return f_floor(f_div(self, other));
+}
+static VALUE
+nurat_mod(VALUE self, VALUE other)
+{
+  VALUE val = f_floor(f_div(self, other));
+  return f_sub(self, f_mul(other, val));
+}
+
+static VALUE
+nurat_divmod(VALUE self, VALUE other)
+{
+  VALUE val = f_floor(f_div(self, other));
+  return rb_assoc_new(val, f_sub(self, f_mul(other, val)));
+}
+
+static VALUE
+nurat_quot(VALUE self, VALUE other)
+{
+  return f_truncate(f_div(self, other));
+}
+static VALUE
+nurat_rem(VALUE self, VALUE other)
+{
+  VALUE val = f_truncate(f_div(self, other));
+  return f_sub(self, f_mul(other, val));
+}
+
+static VALUE
+nurat_quotrem(VALUE self, VALUE other)
+{
+  VALUE val = f_truncate(f_div(self, other));
+  return rb_assoc_new(val, f_sub(self, f_mul(other, val)));
+}
+
+static VALUE
+nurat_abs(VALUE self)
+{
+  if (!f_negative_p(self))
+    return self;
+  else
+    return f_negate(self);
+}
+
+static VALUE
+nurat_true(VALUE self)
+{
+  return Qtrue;
+}
+
+static VALUE
+nurat_floor(VALUE self)
+{
+  get_dat1(self);
+  return f_idiv(dat->num, dat->den);
+}
+
+static VALUE
+nurat_ceil(VALUE self)
+{
+  get_dat1(self);
+  return f_negate(f_idiv(f_negate(dat->num), dat->den));
+}
+
+static VALUE
+nurat_truncate(VALUE self)
+{
+  get_dat1(self);
+  if (f_negative_p(dat->num))
+    return f_negate(f_idiv(f_negate(dat->num), dat->den));
+  return f_idiv(dat->num, dat->den);
+}
+
+static VALUE
+nurat_round(VALUE self)
+{
+  get_dat1(self);
+
+  if (f_negative_p(dat->num)) {
+    VALUE num, den;
+
+    num = f_negate(dat->num);
+    num = f_add(f_mul(num, TWO), dat->den);
+    den = f_mul(dat->den, TWO);
+    return f_negate(f_idiv(num, den));
+  } else {
+    VALUE num = f_add(f_mul(dat->num, TWO), dat->den);
+    VALUE den = f_mul(dat->den, TWO);
+    return f_idiv(num, den);
+  }
+}
+
+static VALUE
+nurat_to_f(VALUE self)
+{
+  get_dat1(self);
+  return f_div(f_to_f(dat->num), dat->den); /* enough? */
+}
+
+static VALUE
+nurat_to_r(VALUE self)
+{
+  return self;
+}
+
+static VALUE
+nurat_hash(VALUE self)
+{
+  get_dat1(self);
+  return f_xor(dat->num, dat->den);
+}
+
+static VALUE
+nurat_to_s(VALUE self)
+{
+  get_dat1(self);
+
+  if (f_one_p(dat->den))
+    return f_to_s(dat->num);
+  else
+    return rb_funcall(rb_mKernel, id_format, 3,
+		      rb_str_new2("%d/%d"), dat->num, dat->den);
+}
+
+static VALUE
+nurat_inspect(VALUE self)
+{
+  get_dat1(self);
+  return rb_funcall(rb_mKernel, id_format, 3,
+		    rb_str_new2("Rational(%d, %d)"), dat->num, dat->den);
+}
+
+static VALUE
+nurat_marshal_dump(VALUE self)
+{
+  get_dat1(self);
+  return rb_assoc_new(dat->num, dat->den);
+}
+
+static VALUE
+nurat_marshal_load(VALUE self, VALUE a)
+{
+  get_dat1(self);
+  dat->num = RARRAY_PTR(a)[0];
+  dat->den = RARRAY_PTR(a)[1];
+  return self;
+}
+
+/* --- */
+
+VALUE
+rb_rational_raw(VALUE x, VALUE y)
+{
+  return nurat_s_new_internal(rb_cRational, x, y);
+}
+
+VALUE
+rb_rational_new(VALUE x, VALUE y)
+{
+  return nurat_s_canonicalize_internal(rb_cRational, x, y);
+}
+
+static VALUE nurat_s_convert(int argc, VALUE *argv, VALUE klass);
+
+VALUE
+rb_Rational(VALUE x, VALUE y)
+{
+  VALUE a[2];
+  a[0] = x;
+  a[1] = y;
+  return nurat_s_convert(2, a, rb_cRational);
+}
+
+static VALUE
+nilclass_to_r(VALUE self)
+{
+  return rb_rational_new1(INT2FIX(0));
+}
+
+static VALUE
+integer_to_r(VALUE self)
+{
+  return rb_rational_new1(self);
+}
+
+#include <float.h>
+
+static VALUE
+float_decode(VALUE self)
+{
+  double f;
+  int n;
+
+  f = frexp(RFLOAT_VALUE(self), &n);
+  f = ldexp(f, DBL_MANT_DIG);
+  n -= DBL_MANT_DIG;
+  return rb_assoc_new(f_to_i(rb_float_new(f)), INT2FIX(n));
+}
+
+static VALUE
+float_to_r(VALUE self)
+{
+  VALUE a = float_decode(self);
+  return f_mul(RARRAY_PTR(a)[0], f_expt(INT2FIX(FLT_RADIX), RARRAY_PTR(a)[1]));
+}
+
+static VALUE rat_pat, an_e_pat, a_dot_pat, underscores_pat, an_underscore;
+
+#define DIGITS "(?:\\d(?:_\\d|\\d)*)"
+#define NUMERATOR "(?:" DIGITS "?\\.)?" DIGITS "(?:[eE][-+]?" DIGITS ")?"
+#define DENOMINATOR "[-+]?" DIGITS
+#define PATTERN "\\A([-+])?(" NUMERATOR ")(?:\\/(" DENOMINATOR "))?"
+
+static void
+make_patterns(void)
+{
+  static char *rat_pat_source = PATTERN;
+  static char *an_e_pat_source = "[eE]";
+  static char *a_dot_pat_source = "\\.";
+  static char *underscores_pat_source = "_+";
+
+  rat_pat = rb_reg_new(rat_pat_source, strlen(rat_pat_source), 0);
+  rb_global_variable(&rat_pat);
+
+  an_e_pat = rb_reg_new(an_e_pat_source, strlen(an_e_pat_source), 0);
+  rb_global_variable(&an_e_pat);
+
+  a_dot_pat = rb_reg_new(a_dot_pat_source, strlen(a_dot_pat_source), 0);
+  rb_global_variable(&a_dot_pat);
+
+  underscores_pat = rb_reg_new(underscores_pat_source,
+			       strlen(underscores_pat_source), 0);
+  rb_global_variable(&underscores_pat);
+
+  an_underscore = rb_str_new2("_");
+  rb_global_variable(&an_underscore);
+}
+
+#define id_strip rb_intern("strip")
+#define f_strip(x) rb_funcall(x, id_strip, 0)
+
+#define id_match rb_intern("match")
+#define f_match(x,y) rb_funcall(x, id_match, 1, y)
+
+#define id_aref rb_intern("[]")
+#define f_aref(x,y) rb_funcall(x, id_aref, 1, y)
+
+#define id_post_match rb_intern("post_match")
+#define f_post_match(x) rb_funcall(x, id_post_match, 0)
+
+#define id_split rb_intern("split")
+#define f_split(x,y) rb_funcall(x, id_split, 1, y)
+
+#include <ctype.h>
+
+static VALUE
+string_to_r_internal(VALUE self)
+{
+  VALUE s, m;
+
+  s = f_strip(self);
+
+  if (RSTRING_LEN(s) == 0)
+    return rb_assoc_new(Qnil, self);
+
+  m = f_match(rat_pat, s);
+
+  if (!NIL_P(m)) {
+    VALUE v, ifp, exp, ip, fp;
+    VALUE si = f_aref(m, INT2FIX(1));
+    VALUE nu = f_aref(m, INT2FIX(2));
+    VALUE de = f_aref(m, INT2FIX(3));
+    VALUE re = f_post_match(m);
+
+    {
+      VALUE a;
+
+      a = f_split(nu, an_e_pat);
+      ifp = RARRAY_PTR(a)[0];
+      if (RARRAY_LEN(a) != 2)
+	exp = Qnil;
+      else
+	exp = RARRAY_PTR(a)[1];
+
+      a = f_split(ifp, a_dot_pat);
+      ip = RARRAY_PTR(a)[0];
+      if (RARRAY_LEN(a) != 2)
+	fp = Qnil;
+      else
+	fp = RARRAY_PTR(a)[1];
+    }
+
+    v = rb_rational_new1(f_to_i(ip));
+
+    if (!NIL_P(fp)) {
+      char *p = StringValuePtr(fp);
+      long count = 0;
+      VALUE l;
+
+      while (*p) {
+	if (isdigit(*p))
+	  count++;
+	p++;
+      }
+
+      l = f_expt(INT2FIX(10), LONG2NUM(count));
+      v = f_mul(v, l);
+      v = f_add(v, f_to_i(fp));
+      v = f_div(v, l);
+    }
+    if (!NIL_P(exp))
+      v = f_mul(v, f_expt(INT2FIX(10), f_to_i(exp)));
+    if (!NIL_P(si) && *StringValuePtr(si) == '-')
+      v = f_negate(v);
+    if (!NIL_P(de))
+      v = f_div(v, f_to_i(de));
+
+    return rb_assoc_new(v, re);
+  }
+  return rb_assoc_new(Qnil, self);
+}
+
+static VALUE
+string_to_r_strict(VALUE self)
+{
+  VALUE a = string_to_r_internal(self);
+  if (NIL_P(RARRAY_PTR(a)[0]) || RSTRING_LEN(RARRAY_PTR(a)[1]) > 0) {
+    VALUE s = f_inspect(self);
+    rb_raise(rb_eArgError, "invalid value for Rational: %s",
+	     StringValuePtr(s));
+  }
+  return RARRAY_PTR(a)[0];
+}
+
+#define id_gsub rb_intern("gsub")
+#define f_gsub(x,y,z) rb_funcall(x, id_gsub, 2, y, z)
+
+static VALUE
+string_to_r(VALUE self)
+{
+  VALUE s = f_gsub(self, underscores_pat, an_underscore);
+  VALUE a = string_to_r_internal(s);
+  if (!NIL_P(RARRAY_PTR(a)[0]))
+    return RARRAY_PTR(a)[0];
+  return rb_rational_new1(INT2FIX(0));
+}
+
+#define id_to_r rb_intern("to_r")
+#define f_to_r(x) rb_funcall(x, id_to_r, 0)
+
+static VALUE
+nurat_s_convert(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE a1, a2;
+
+  a1 = Qnil;
+  a2 = Qnil;
+  rb_scan_args(argc, argv, "02", &a1, &a2);
+
+  switch (TYPE(a1)) {
+  case T_COMPLEX:
+    if (k_float_p(RCOMPLEX(a1)->image) || !f_zero_p(RCOMPLEX(a1)->image)) {
+      VALUE s = f_to_s(a1);
+      rb_raise(rb_eRangeError, "can't accept %s",
+	       StringValuePtr(s));
+    }
+    a1 = RCOMPLEX(a1)->real;
+  }
+
+  switch (TYPE(a2)) {
+  case T_COMPLEX:
+    if (k_float_p(RCOMPLEX(a2)->image) || !f_zero_p(RCOMPLEX(a2)->image)) {
+      VALUE s = f_to_s(a2);
+      rb_raise(rb_eRangeError, "can't accept %s",
+	       StringValuePtr(s));
+    }
+    a2 = RCOMPLEX(a2)->real;
+  }
+
+  switch (TYPE(a1)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+    break;
+  case T_FLOAT:
+    a1 = f_to_r(a1);
+    break;
+  case T_STRING:
+    a1 = string_to_r_strict(a1);
+    break;
+  }
+
+  switch (TYPE(a2)) {
+  case T_FIXNUM:
+  case T_BIGNUM:
+    break;
+  case T_FLOAT:
+    a2 = f_to_r(a2);
+    break;
+  case T_STRING:
+    a2 = string_to_r_strict(a2);
+    break;
+  }
+
+  switch (TYPE(a1)) {
+  case T_RATIONAL:
+    if (NIL_P(a2) || f_zero_p(a2))
+      return a1;
+    else
+      return f_div(a1, a2);
+  }
+
+  switch (TYPE(a2)) {
+  case T_RATIONAL:
+    return f_div(a1, a2);
+  }
+
+  {
+    VALUE argv2[2];
+    argv2[0] = a1;
+    argv2[1] = a2;
+    return nurat_s_new(argc, argv2, klass);
+  }
+}
+
+static VALUE
+nurat_s_induced_from(VALUE klass, VALUE n)
+{
+  return f_to_r(n);
+}
+
+void
+Init_Rational(void)
+{
+  assert(fprintf(stderr, "assert() is now active\n"));
+
+  id_Unify = rb_intern("Unify");
+  id_cmp = rb_intern("<=>");
+  id_coerce = rb_intern("coerce");
+  id_convert = rb_intern("convert");
+  id_equal_p = rb_intern("==");
+  id_expt = rb_intern("**");
+  id_floor = rb_intern("floor");
+  id_format = rb_intern("format");
+  id_idiv = rb_intern("div");
+  id_inspect = rb_intern("inspect");
+  id_negate = rb_intern("-@");
+  id_new = rb_intern("new");
+  id_new_bang = rb_intern("new!");
+  id_to_f = rb_intern("to_f");
+  id_to_i = rb_intern("to_i");
+  id_to_s = rb_intern("to_s");
+  id_truncate = rb_intern("truncate");
+
+  rb_cRational = rb_define_class(RATIONAL_NAME, rb_cNumeric);
+
+  rb_define_alloc_func(rb_cRational, nurat_s_alloc);
+  rb_funcall(rb_cRational, rb_intern("private_class_method"), 1,
+	     ID2SYM(rb_intern("allocate")));
+
+  rb_define_singleton_method(rb_cRational, "new!", nurat_s_new_bang, -1);
+  rb_funcall(rb_cRational, rb_intern("private_class_method"), 1,
+	     ID2SYM(rb_intern("new!")));
+
+  rb_define_singleton_method(rb_cRational, "new", nurat_s_new, -1);
+  rb_funcall(rb_cRational, rb_intern("private_class_method"), 1,
+	     ID2SYM(rb_intern("new")));
+
+  rb_define_global_function(RATIONAL_NAME, nurat_f_rational, -1);
+
+  rb_define_method(rb_cRational, "numerator", nurat_numerator, 0);
+  rb_define_method(rb_cRational, "denominator", nurat_denominator, 0);
+
+  rb_define_method(rb_cRational, "+", nurat_add, 1);
+  rb_define_method(rb_cRational, "-", nurat_sub, 1);
+  rb_define_method(rb_cRational, "*", nurat_mul, 1);
+  rb_define_method(rb_cRational, "/", nurat_div, 1);
+  rb_define_method(rb_cRational, "fdiv", nurat_fdiv, 1);
+  rb_define_method(rb_cRational, "**", nurat_expt, 1);
+
+  rb_define_method(rb_cRational, "<=>", nurat_cmp, 1);
+  rb_define_method(rb_cRational, "==", nurat_equal_p, 1);
+  rb_define_method(rb_cRational, "coerce", nurat_coerce, 1);
+
+  rb_define_method(rb_cRational, "div", nurat_idiv, 1);
+#if NUBY
+  rb_define_method(rb_cRational, "//", nurat_idiv, 1);
+#endif
+  rb_define_method(rb_cRational, "modulo", nurat_mod, 1);
+  rb_define_method(rb_cRational, "%", nurat_mod, 1);
+  rb_define_method(rb_cRational, "divmod", nurat_divmod, 1);
+
+#if 0
+  rb_define_method(rb_cRational, "quot", nurat_quot, 1);
+#endif
+  rb_define_method(rb_cRational, "remainder", nurat_rem, 1);
+#if 0
+  rb_define_method(rb_cRational, "quotrem", nurat_quotrem, 1);
+#endif
+
+  rb_define_method(rb_cRational, "abs", nurat_abs, 0);
+
+#if 0
+  rb_define_method(rb_cRational, "rational?", nurat_true, 0);
+  rb_define_method(rb_cRational, "exact?", nurat_true, 0);
+#endif
+
+  rb_define_method(rb_cRational, "floor", nurat_floor, 0);
+  rb_define_method(rb_cRational, "ceil", nurat_ceil, 0);
+  rb_define_method(rb_cRational, "truncate", nurat_truncate, 0);
+  rb_define_method(rb_cRational, "round", nurat_round, 0);
+
+  rb_define_method(rb_cRational, "to_i", nurat_truncate, 0);
+  rb_define_method(rb_cRational, "to_f", nurat_to_f, 0);
+  rb_define_method(rb_cRational, "to_r", nurat_to_r, 0);
+
+  rb_define_method(rb_cRational, "hash", nurat_hash, 0);
+
+  rb_define_method(rb_cRational, "to_s", nurat_to_s, 0);
+  rb_define_method(rb_cRational, "inspect", nurat_inspect, 0);
+
+  rb_define_method(rb_cRational, "marshal_dump", nurat_marshal_dump, 0);
+  rb_define_method(rb_cRational, "marshal_load", nurat_marshal_load, 1);
+
+  /* --- */
+
+  rb_define_method(rb_cNilClass, "to_r", nilclass_to_r, 0);
+  rb_define_method(rb_cInteger, "to_r", integer_to_r, 0);
+  rb_define_method(rb_cFloat, "to_r", float_to_r, 0);
+
+  make_patterns();
+
+  rb_define_method(rb_cString, "to_r", string_to_r, 0);
+
+  rb_define_singleton_method(rb_cRational, "convert", nurat_s_convert, -1);
+  rb_funcall(rb_cRational, rb_intern("private_class_method"), 1,
+	     ID2SYM(rb_intern("convert")));
+
+  rb_include_module(rb_cRational, rb_mPrecision);
+  rb_define_singleton_method(rb_cRational, "induced_from",
+			     nurat_s_induced_from, 1);
+}

Property changes on: rational.c
___________________________________________________________________
Name: svn:mime-type
   + text/plain


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]