Ruby  2.0.0p247(2013-06-27revision41674)
complex.c
Go to the documentation of this file.
00001 /*
00002   complex.c: Coded by Tadayoshi Funaba 2008-2012
00003 
00004   This implementation is based on Keiju Ishitsuka's Complex library
00005   which is written in ruby.
00006 */
00007 
00008 #include "ruby.h"
00009 #include "internal.h"
00010 #include <math.h>
00011 
00012 #define NDEBUG
00013 #include <assert.h>
00014 
00015 #define ZERO INT2FIX(0)
00016 #define ONE INT2FIX(1)
00017 #define TWO INT2FIX(2)
00018 
00019 VALUE rb_cComplex;
00020 
00021 static ID id_abs, id_abs2, id_arg, id_cmp, id_conj, id_convert,
00022     id_denominator, id_divmod, id_eqeq_p, id_expt, id_fdiv,  id_floor,
00023     id_idiv, id_imag, id_inspect, id_negate, id_numerator, id_quo,
00024     id_real, id_real_p, id_to_f, id_to_i, id_to_r, id_to_s,
00025     id_i_real, id_i_imag;
00026 
00027 #define f_boolcast(x) ((x) ? Qtrue : Qfalse)
00028 
00029 #define binop(n,op) \
00030 inline static VALUE \
00031 f_##n(VALUE x, VALUE y)\
00032 {\
00033     return rb_funcall(x, (op), 1, y);\
00034 }
00035 
00036 #define fun1(n) \
00037 inline static VALUE \
00038 f_##n(VALUE x)\
00039 {\
00040     return rb_funcall(x, id_##n, 0);\
00041 }
00042 
00043 #define fun2(n) \
00044 inline static VALUE \
00045 f_##n(VALUE x, VALUE y)\
00046 {\
00047     return rb_funcall(x, id_##n, 1, y);\
00048 }
00049 
00050 #define math1(n) \
00051 inline static VALUE \
00052 m_##n(VALUE x)\
00053 {\
00054     return rb_funcall(rb_mMath, id_##n, 1, x);\
00055 }
00056 
00057 #define math2(n) \
00058 inline static VALUE \
00059 m_##n(VALUE x, VALUE y)\
00060 {\
00061     return rb_funcall(rb_mMath, id_##n, 2, x, y);\
00062 }
00063 
00064 #define PRESERVE_SIGNEDZERO
00065 
00066 inline static VALUE
00067 f_add(VALUE x, VALUE y)
00068 {
00069 #ifndef PRESERVE_SIGNEDZERO
00070     if (FIXNUM_P(y) && FIX2LONG(y) == 0)
00071         return x;
00072     else if (FIXNUM_P(x) && FIX2LONG(x) == 0)
00073         return y;
00074 #endif
00075     return rb_funcall(x, '+', 1, y);
00076 }
00077 
00078 inline static VALUE
00079 f_cmp(VALUE x, VALUE y)
00080 {
00081     if (FIXNUM_P(x) && FIXNUM_P(y)) {
00082         long c = FIX2LONG(x) - FIX2LONG(y);
00083         if (c > 0)
00084             c = 1;
00085         else if (c < 0)
00086             c = -1;
00087         return INT2FIX(c);
00088     }
00089     return rb_funcall(x, id_cmp, 1, y);
00090 }
00091 
00092 inline static VALUE
00093 f_div(VALUE x, VALUE y)
00094 {
00095     if (FIXNUM_P(y) && FIX2LONG(y) == 1)
00096         return x;
00097     return rb_funcall(x, '/', 1, y);
00098 }
00099 
00100 inline static VALUE
00101 f_gt_p(VALUE x, VALUE y)
00102 {
00103     if (FIXNUM_P(x) && FIXNUM_P(y))
00104         return f_boolcast(FIX2LONG(x) > FIX2LONG(y));
00105     return rb_funcall(x, '>', 1, y);
00106 }
00107 
00108 inline static VALUE
00109 f_lt_p(VALUE x, VALUE y)
00110 {
00111     if (FIXNUM_P(x) && FIXNUM_P(y))
00112         return f_boolcast(FIX2LONG(x) < FIX2LONG(y));
00113     return rb_funcall(x, '<', 1, y);
00114 }
00115 
00116 binop(mod, '%')
00117 
00118 inline static VALUE
00119 f_mul(VALUE x, VALUE y)
00120 {
00121 #ifndef PRESERVE_SIGNEDZERO
00122     if (FIXNUM_P(y)) {
00123         long iy = FIX2LONG(y);
00124         if (iy == 0) {
00125             if (FIXNUM_P(x) || RB_TYPE_P(x, T_BIGNUM))
00126                 return ZERO;
00127         }
00128         else if (iy == 1)
00129             return x;
00130     }
00131     else if (FIXNUM_P(x)) {
00132         long ix = FIX2LONG(x);
00133         if (ix == 0) {
00134             if (FIXNUM_P(y) || RB_TYPE_P(y, T_BIGNUM))
00135                 return ZERO;
00136         }
00137         else if (ix == 1)
00138             return y;
00139     }
00140 #endif
00141     return rb_funcall(x, '*', 1, y);
00142 }
00143 
00144 inline static VALUE
00145 f_sub(VALUE x, VALUE y)
00146 {
00147 #ifndef PRESERVE_SIGNEDZERO
00148     if (FIXNUM_P(y) && FIX2LONG(y) == 0)
00149         return x;
00150 #endif
00151     return rb_funcall(x, '-', 1, y);
00152 }
00153 
00154 fun1(abs)
00155 fun1(abs2)
00156 fun1(arg)
00157 fun1(conj)
00158 fun1(denominator)
00159 fun1(floor)
00160 fun1(imag)
00161 fun1(inspect)
00162 fun1(negate)
00163 fun1(numerator)
00164 fun1(real)
00165 fun1(real_p)
00166 
00167 inline static VALUE
00168 f_to_i(VALUE x)
00169 {
00170     if (RB_TYPE_P(x, T_STRING))
00171         return rb_str_to_inum(x, 10, 0);
00172     return rb_funcall(x, id_to_i, 0);
00173 }
00174 inline static VALUE
00175 f_to_f(VALUE x)
00176 {
00177     if (RB_TYPE_P(x, T_STRING))
00178         return DBL2NUM(rb_str_to_dbl(x, 0));
00179     return rb_funcall(x, id_to_f, 0);
00180 }
00181 
00182 fun1(to_r)
00183 fun1(to_s)
00184 
00185 fun2(divmod)
00186 
00187 inline static VALUE
00188 f_eqeq_p(VALUE x, VALUE y)
00189 {
00190     if (FIXNUM_P(x) && FIXNUM_P(y))
00191         return f_boolcast(FIX2LONG(x) == FIX2LONG(y));
00192     return rb_funcall(x, id_eqeq_p, 1, y);
00193 }
00194 
00195 fun2(expt)
00196 fun2(fdiv)
00197 fun2(idiv)
00198 fun2(quo)
00199 
00200 inline static VALUE
00201 f_negative_p(VALUE x)
00202 {
00203     if (FIXNUM_P(x))
00204         return f_boolcast(FIX2LONG(x) < 0);
00205     return rb_funcall(x, '<', 1, ZERO);
00206 }
00207 
00208 #define f_positive_p(x) (!f_negative_p(x))
00209 
00210 inline static VALUE
00211 f_zero_p(VALUE x)
00212 {
00213     switch (TYPE(x)) {
00214       case T_FIXNUM:
00215         return f_boolcast(FIX2LONG(x) == 0);
00216       case T_BIGNUM:
00217         return Qfalse;
00218       case T_RATIONAL:
00219       {
00220           VALUE num = RRATIONAL(x)->num;
00221 
00222           return f_boolcast(FIXNUM_P(num) && FIX2LONG(num) == 0);
00223       }
00224     }
00225     return rb_funcall(x, id_eqeq_p, 1, ZERO);
00226 }
00227 
00228 #define f_nonzero_p(x) (!f_zero_p(x))
00229 
00230 inline static VALUE
00231 f_one_p(VALUE x)
00232 {
00233     switch (TYPE(x)) {
00234       case T_FIXNUM:
00235         return f_boolcast(FIX2LONG(x) == 1);
00236       case T_BIGNUM:
00237         return Qfalse;
00238       case T_RATIONAL:
00239       {
00240           VALUE num = RRATIONAL(x)->num;
00241           VALUE den = RRATIONAL(x)->den;
00242 
00243           return f_boolcast(FIXNUM_P(num) && FIX2LONG(num) == 1 &&
00244                             FIXNUM_P(den) && FIX2LONG(den) == 1);
00245       }
00246     }
00247     return rb_funcall(x, id_eqeq_p, 1, ONE);
00248 }
00249 
00250 inline static VALUE
00251 f_kind_of_p(VALUE x, VALUE c)
00252 {
00253     return rb_obj_is_kind_of(x, c);
00254 }
00255 
00256 inline static VALUE
00257 k_numeric_p(VALUE x)
00258 {
00259     return f_kind_of_p(x, rb_cNumeric);
00260 }
00261 
00262 inline static VALUE
00263 k_integer_p(VALUE x)
00264 {
00265     return f_kind_of_p(x, rb_cInteger);
00266 }
00267 
00268 inline static VALUE
00269 k_fixnum_p(VALUE x)
00270 {
00271     return f_kind_of_p(x, rb_cFixnum);
00272 }
00273 
00274 inline static VALUE
00275 k_bignum_p(VALUE x)
00276 {
00277     return f_kind_of_p(x, rb_cBignum);
00278 }
00279 
00280 inline static VALUE
00281 k_float_p(VALUE x)
00282 {
00283     return f_kind_of_p(x, rb_cFloat);
00284 }
00285 
00286 inline static VALUE
00287 k_rational_p(VALUE x)
00288 {
00289     return f_kind_of_p(x, rb_cRational);
00290 }
00291 
00292 inline static VALUE
00293 k_complex_p(VALUE x)
00294 {
00295     return f_kind_of_p(x, rb_cComplex);
00296 }
00297 
00298 #define k_exact_p(x) (!k_float_p(x))
00299 #define k_inexact_p(x) k_float_p(x)
00300 
00301 #define k_exact_zero_p(x) (k_exact_p(x) && f_zero_p(x))
00302 #define k_exact_one_p(x) (k_exact_p(x) && f_one_p(x))
00303 
00304 #define get_dat1(x) \
00305     struct RComplex *dat;\
00306     dat = ((struct RComplex *)(x))
00307 
00308 #define get_dat2(x,y) \
00309     struct RComplex *adat, *bdat;\
00310     adat = ((struct RComplex *)(x));\
00311     bdat = ((struct RComplex *)(y))
00312 
00313 inline static VALUE
00314 nucomp_s_new_internal(VALUE klass, VALUE real, VALUE imag)
00315 {
00316     NEWOBJ_OF(obj, struct RComplex, klass, T_COMPLEX);
00317 
00318     obj->real = real;
00319     obj->imag = imag;
00320 
00321     return (VALUE)obj;
00322 }
00323 
00324 static VALUE
00325 nucomp_s_alloc(VALUE klass)
00326 {
00327     return nucomp_s_new_internal(klass, ZERO, ZERO);
00328 }
00329 
00330 #if 0
00331 static VALUE
00332 nucomp_s_new_bang(int argc, VALUE *argv, VALUE klass)
00333 {
00334     VALUE real, imag;
00335 
00336     switch (rb_scan_args(argc, argv, "11", &real, &imag)) {
00337       case 1:
00338         if (!k_numeric_p(real))
00339             real = f_to_i(real);
00340         imag = ZERO;
00341         break;
00342       default:
00343         if (!k_numeric_p(real))
00344             real = f_to_i(real);
00345         if (!k_numeric_p(imag))
00346             imag = f_to_i(imag);
00347         break;
00348     }
00349 
00350     return nucomp_s_new_internal(klass, real, imag);
00351 }
00352 #endif
00353 
00354 inline static VALUE
00355 f_complex_new_bang1(VALUE klass, VALUE x)
00356 {
00357     assert(!k_complex_p(x));
00358     return nucomp_s_new_internal(klass, x, ZERO);
00359 }
00360 
00361 inline static VALUE
00362 f_complex_new_bang2(VALUE klass, VALUE x, VALUE y)
00363 {
00364     assert(!k_complex_p(x));
00365     assert(!k_complex_p(y));
00366     return nucomp_s_new_internal(klass, x, y);
00367 }
00368 
00369 #ifdef CANONICALIZATION_FOR_MATHN
00370 #define CANON
00371 #endif
00372 
00373 #ifdef CANON
00374 static int canonicalization = 0;
00375 
00376 RUBY_FUNC_EXPORTED void
00377 nucomp_canonicalization(int f)
00378 {
00379     canonicalization = f;
00380 }
00381 #endif
00382 
00383 inline static void
00384 nucomp_real_check(VALUE num)
00385 {
00386     switch (TYPE(num)) {
00387       case T_FIXNUM:
00388       case T_BIGNUM:
00389       case T_FLOAT:
00390       case T_RATIONAL:
00391         break;
00392       default:
00393         if (!k_numeric_p(num) || !f_real_p(num))
00394             rb_raise(rb_eTypeError, "not a real");
00395     }
00396 }
00397 
00398 inline static VALUE
00399 nucomp_s_canonicalize_internal(VALUE klass, VALUE real, VALUE imag)
00400 {
00401 #ifdef CANON
00402 #define CL_CANON
00403 #ifdef CL_CANON
00404     if (k_exact_zero_p(imag) && canonicalization)
00405         return real;
00406 #else
00407     if (f_zero_p(imag) && canonicalization)
00408         return real;
00409 #endif
00410 #endif
00411     if (f_real_p(real) && f_real_p(imag))
00412         return nucomp_s_new_internal(klass, real, imag);
00413     else if (f_real_p(real)) {
00414         get_dat1(imag);
00415 
00416         return nucomp_s_new_internal(klass,
00417                                      f_sub(real, dat->imag),
00418                                      f_add(ZERO, dat->real));
00419     }
00420     else if (f_real_p(imag)) {
00421         get_dat1(real);
00422 
00423         return nucomp_s_new_internal(klass,
00424                                      dat->real,
00425                                      f_add(dat->imag, imag));
00426     }
00427     else {
00428         get_dat2(real, imag);
00429 
00430         return nucomp_s_new_internal(klass,
00431                                      f_sub(adat->real, bdat->imag),
00432                                      f_add(adat->imag, bdat->real));
00433     }
00434 }
00435 
00436 /*
00437  * call-seq:
00438  *    Complex.rect(real[, imag])         ->  complex
00439  *    Complex.rectangular(real[, imag])  ->  complex
00440  *
00441  * Returns a complex object which denotes the given rectangular form.
00442  *
00443  *    Complex.rectangular(1, 2)  #=> (1+2i)
00444  */
00445 static VALUE
00446 nucomp_s_new(int argc, VALUE *argv, VALUE klass)
00447 {
00448     VALUE real, imag;
00449 
00450     switch (rb_scan_args(argc, argv, "11", &real, &imag)) {
00451       case 1:
00452         nucomp_real_check(real);
00453         imag = ZERO;
00454         break;
00455       default:
00456         nucomp_real_check(real);
00457         nucomp_real_check(imag);
00458         break;
00459     }
00460 
00461     return nucomp_s_canonicalize_internal(klass, real, imag);
00462 }
00463 
00464 inline static VALUE
00465 f_complex_new1(VALUE klass, VALUE x)
00466 {
00467     assert(!k_complex_p(x));
00468     return nucomp_s_canonicalize_internal(klass, x, ZERO);
00469 }
00470 
00471 inline static VALUE
00472 f_complex_new2(VALUE klass, VALUE x, VALUE y)
00473 {
00474     assert(!k_complex_p(x));
00475     return nucomp_s_canonicalize_internal(klass, x, y);
00476 }
00477 
00478 /*
00479  * call-seq:
00480  *    Complex(x[, y])  ->  numeric
00481  *
00482  * Returns x+i*y;
00483  *
00484  *    Complex(1, 2)    #=> (1+2i)
00485  *    Complex('1+2i')  #=> (1+2i)
00486  *
00487  * Syntax of string form:
00488  *
00489  *   string form = extra spaces , complex , extra spaces ;
00490  *   complex = real part | [ sign ] , imaginary part
00491  *           | real part , sign , imaginary part
00492  *           | rational , "@" , rational ;
00493  *   real part = rational ;
00494  *   imaginary part = imaginary unit | unsigned rational , imaginary unit ;
00495  *   rational = [ sign ] , unsigned rational ;
00496  *   unsigned rational = numerator | numerator , "/" , denominator ;
00497  *   numerator = integer part | fractional part | integer part , fractional part ;
00498  *   denominator = digits ;
00499  *   integer part = digits ;
00500  *   fractional part = "." , digits , [ ( "e" | "E" ) , [ sign ] , digits ] ;
00501  *   imaginary unit = "i" | "I" | "j" | "J" ;
00502  *   sign = "-" | "+" ;
00503  *   digits = digit , { digit | "_" , digit };
00504  *   digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
00505  *   extra spaces = ? \s* ? ;
00506  *
00507  * See String#to_c.
00508  */
00509 static VALUE
00510 nucomp_f_complex(int argc, VALUE *argv, VALUE klass)
00511 {
00512     return rb_funcall2(rb_cComplex, id_convert, argc, argv);
00513 }
00514 
00515 #define imp1(n) \
00516 inline static VALUE \
00517 m_##n##_bang(VALUE x)\
00518 {\
00519     return rb_math_##n(x);\
00520 }
00521 
00522 #define imp2(n) \
00523 inline static VALUE \
00524 m_##n##_bang(VALUE x, VALUE y)\
00525 {\
00526     return rb_math_##n(x, y);\
00527 }
00528 
00529 imp2(atan2)
00530 imp1(cos)
00531 imp1(cosh)
00532 imp1(exp)
00533 imp2(hypot)
00534 
00535 #define m_hypot(x,y) m_hypot_bang((x),(y))
00536 
00537 static VALUE
00538 m_log_bang(VALUE x)
00539 {
00540     return rb_math_log(1, &x);
00541 }
00542 
00543 imp1(sin)
00544 imp1(sinh)
00545 imp1(sqrt)
00546 
00547 static VALUE
00548 m_cos(VALUE x)
00549 {
00550     if (f_real_p(x))
00551         return m_cos_bang(x);
00552     {
00553         get_dat1(x);
00554         return f_complex_new2(rb_cComplex,
00555                               f_mul(m_cos_bang(dat->real),
00556                                     m_cosh_bang(dat->imag)),
00557                               f_mul(f_negate(m_sin_bang(dat->real)),
00558                                     m_sinh_bang(dat->imag)));
00559     }
00560 }
00561 
00562 static VALUE
00563 m_sin(VALUE x)
00564 {
00565     if (f_real_p(x))
00566         return m_sin_bang(x);
00567     {
00568         get_dat1(x);
00569         return f_complex_new2(rb_cComplex,
00570                               f_mul(m_sin_bang(dat->real),
00571                                     m_cosh_bang(dat->imag)),
00572                               f_mul(m_cos_bang(dat->real),
00573                                     m_sinh_bang(dat->imag)));
00574     }
00575 }
00576 
00577 #if 0
00578 static VALUE
00579 m_sqrt(VALUE x)
00580 {
00581     if (f_real_p(x)) {
00582         if (f_positive_p(x))
00583             return m_sqrt_bang(x);
00584         return f_complex_new2(rb_cComplex, ZERO, m_sqrt_bang(f_negate(x)));
00585     }
00586     else {
00587         get_dat1(x);
00588 
00589         if (f_negative_p(dat->imag))
00590             return f_conj(m_sqrt(f_conj(x)));
00591         else {
00592             VALUE a = f_abs(x);
00593             return f_complex_new2(rb_cComplex,
00594                                   m_sqrt_bang(f_div(f_add(a, dat->real), TWO)),
00595                                   m_sqrt_bang(f_div(f_sub(a, dat->real), TWO)));
00596         }
00597     }
00598 }
00599 #endif
00600 
00601 inline static VALUE
00602 f_complex_polar(VALUE klass, VALUE x, VALUE y)
00603 {
00604     assert(!k_complex_p(x));
00605     assert(!k_complex_p(y));
00606     return nucomp_s_canonicalize_internal(klass,
00607                                           f_mul(x, m_cos(y)),
00608                                           f_mul(x, m_sin(y)));
00609 }
00610 
00611 /*
00612  * call-seq:
00613  *    Complex.polar(abs[, arg])  ->  complex
00614  *
00615  * Returns a complex object which denotes the given polar form.
00616  *
00617  *    Complex.polar(3, 0)            #=> (3.0+0.0i)
00618  *    Complex.polar(3, Math::PI/2)   #=> (1.836909530733566e-16+3.0i)
00619  *    Complex.polar(3, Math::PI)     #=> (-3.0+3.673819061467132e-16i)
00620  *    Complex.polar(3, -Math::PI/2)  #=> (1.836909530733566e-16-3.0i)
00621  */
00622 static VALUE
00623 nucomp_s_polar(int argc, VALUE *argv, VALUE klass)
00624 {
00625     VALUE abs, arg;
00626 
00627     switch (rb_scan_args(argc, argv, "11", &abs, &arg)) {
00628       case 1:
00629         nucomp_real_check(abs);
00630         arg = ZERO;
00631         break;
00632       default:
00633         nucomp_real_check(abs);
00634         nucomp_real_check(arg);
00635         break;
00636     }
00637     return f_complex_polar(klass, abs, arg);
00638 }
00639 
00640 /*
00641  * call-seq:
00642  *    cmp.real  ->  real
00643  *
00644  * Returns the real part.
00645  *
00646  *    Complex(7).real      #=> 7
00647  *    Complex(9, -4).real  #=> 9
00648  */
00649 static VALUE
00650 nucomp_real(VALUE self)
00651 {
00652     get_dat1(self);
00653     return dat->real;
00654 }
00655 
00656 /*
00657  * call-seq:
00658  *    cmp.imag       ->  real
00659  *    cmp.imaginary  ->  real
00660  *
00661  * Returns the imaginary part.
00662  *
00663  *    Complex(7).imaginary      #=> 0
00664  *    Complex(9, -4).imaginary  #=> -4
00665  */
00666 static VALUE
00667 nucomp_imag(VALUE self)
00668 {
00669     get_dat1(self);
00670     return dat->imag;
00671 }
00672 
00673 /*
00674  * call-seq:
00675  *    -cmp  ->  complex
00676  *
00677  * Returns negation of the value.
00678  *
00679  *    -Complex(1, 2)  #=> (-1-2i)
00680  */
00681 static VALUE
00682 nucomp_negate(VALUE self)
00683 {
00684   get_dat1(self);
00685   return f_complex_new2(CLASS_OF(self),
00686                         f_negate(dat->real), f_negate(dat->imag));
00687 }
00688 
00689 inline static VALUE
00690 f_addsub(VALUE self, VALUE other,
00691          VALUE (*func)(VALUE, VALUE), ID id)
00692 {
00693     if (k_complex_p(other)) {
00694         VALUE real, imag;
00695 
00696         get_dat2(self, other);
00697 
00698         real = (*func)(adat->real, bdat->real);
00699         imag = (*func)(adat->imag, bdat->imag);
00700 
00701         return f_complex_new2(CLASS_OF(self), real, imag);
00702     }
00703     if (k_numeric_p(other) && f_real_p(other)) {
00704         get_dat1(self);
00705 
00706         return f_complex_new2(CLASS_OF(self),
00707                               (*func)(dat->real, other), dat->imag);
00708     }
00709     return rb_num_coerce_bin(self, other, id);
00710 }
00711 
00712 /*
00713  * call-seq:
00714  *    cmp + numeric  ->  complex
00715  *
00716  * Performs addition.
00717  *
00718  *    Complex(2, 3)  + Complex(2, 3)   #=> (4+6i)
00719  *    Complex(900)   + Complex(1)      #=> (901+0i)
00720  *    Complex(-2, 9) + Complex(-9, 2)  #=> (-11+11i)
00721  *    Complex(9, 8)  + 4               #=> (13+8i)
00722  *    Complex(20, 9) + 9.8             #=> (29.8+9i)
00723  */
00724 static VALUE
00725 nucomp_add(VALUE self, VALUE other)
00726 {
00727     return f_addsub(self, other, f_add, '+');
00728 }
00729 
00730 /*
00731  * call-seq:
00732  *    cmp - numeric  ->  complex
00733  *
00734  * Performs subtraction.
00735  *
00736  *    Complex(2, 3)  - Complex(2, 3)   #=> (0+0i)
00737  *    Complex(900)   - Complex(1)      #=> (899+0i)
00738  *    Complex(-2, 9) - Complex(-9, 2)  #=> (7+7i)
00739  *    Complex(9, 8)  - 4               #=> (5+8i)
00740  *    Complex(20, 9) - 9.8             #=> (10.2+9i)
00741  */
00742 static VALUE
00743 nucomp_sub(VALUE self, VALUE other)
00744 {
00745     return f_addsub(self, other, f_sub, '-');
00746 }
00747 
00748 /*
00749  * call-seq:
00750  *    cmp * numeric  ->  complex
00751  *
00752  * Performs multiplication.
00753  *
00754  *    Complex(2, 3)  * Complex(2, 3)   #=> (-5+12i)
00755  *    Complex(900)   * Complex(1)      #=> (900+0i)
00756  *    Complex(-2, 9) * Complex(-9, 2)  #=> (0-85i)
00757  *    Complex(9, 8)  * 4               #=> (36+32i)
00758  *    Complex(20, 9) * 9.8             #=> (196.0+88.2i)
00759  */
00760 static VALUE
00761 nucomp_mul(VALUE self, VALUE other)
00762 {
00763     if (k_complex_p(other)) {
00764         VALUE real, imag;
00765 
00766         get_dat2(self, other);
00767 
00768         real = f_sub(f_mul(adat->real, bdat->real),
00769                      f_mul(adat->imag, bdat->imag));
00770         imag = f_add(f_mul(adat->real, bdat->imag),
00771                      f_mul(adat->imag, bdat->real));
00772 
00773         return f_complex_new2(CLASS_OF(self), real, imag);
00774     }
00775     if (k_numeric_p(other) && f_real_p(other)) {
00776         get_dat1(self);
00777 
00778         return f_complex_new2(CLASS_OF(self),
00779                               f_mul(dat->real, other),
00780                               f_mul(dat->imag, other));
00781     }
00782     return rb_num_coerce_bin(self, other, '*');
00783 }
00784 
00785 inline static VALUE
00786 f_divide(VALUE self, VALUE other,
00787          VALUE (*func)(VALUE, VALUE), ID id)
00788 {
00789     if (k_complex_p(other)) {
00790         int flo;
00791         get_dat2(self, other);
00792 
00793         flo = (k_float_p(adat->real) || k_float_p(adat->imag) ||
00794                k_float_p(bdat->real) || k_float_p(bdat->imag));
00795 
00796         if (f_gt_p(f_abs(bdat->real), f_abs(bdat->imag))) {
00797             VALUE r, n;
00798 
00799             r = (*func)(bdat->imag, bdat->real);
00800             n = f_mul(bdat->real, f_add(ONE, f_mul(r, r)));
00801             if (flo)
00802                 return f_complex_new2(CLASS_OF(self),
00803                                       (*func)(self, n),
00804                                       (*func)(f_negate(f_mul(self, r)), n));
00805             return f_complex_new2(CLASS_OF(self),
00806                                   (*func)(f_add(adat->real,
00807                                                 f_mul(adat->imag, r)), n),
00808                                   (*func)(f_sub(adat->imag,
00809                                                 f_mul(adat->real, r)), n));
00810         }
00811         else {
00812             VALUE r, n;
00813 
00814             r = (*func)(bdat->real, bdat->imag);
00815             n = f_mul(bdat->imag, f_add(ONE, f_mul(r, r)));
00816             if (flo)
00817                 return f_complex_new2(CLASS_OF(self),
00818                                       (*func)(f_mul(self, r), n),
00819                                       (*func)(f_negate(self), n));
00820             return f_complex_new2(CLASS_OF(self),
00821                                   (*func)(f_add(f_mul(adat->real, r),
00822                                                 adat->imag), n),
00823                                   (*func)(f_sub(f_mul(adat->imag, r),
00824                                                 adat->real), n));
00825         }
00826     }
00827     if (k_numeric_p(other) && f_real_p(other)) {
00828         get_dat1(self);
00829 
00830         return f_complex_new2(CLASS_OF(self),
00831                               (*func)(dat->real, other),
00832                               (*func)(dat->imag, other));
00833     }
00834     return rb_num_coerce_bin(self, other, id);
00835 }
00836 
00837 #define rb_raise_zerodiv() rb_raise(rb_eZeroDivError, "divided by 0")
00838 
00839 /*
00840  * call-seq:
00841  *    cmp / numeric     ->  complex
00842  *    cmp.quo(numeric)  ->  complex
00843  *
00844  * Performs division.
00845  *
00846  *    Complex(2, 3)  / Complex(2, 3)   #=> ((1/1)+(0/1)*i)
00847  *    Complex(900)   / Complex(1)      #=> ((900/1)+(0/1)*i)
00848  *    Complex(-2, 9) / Complex(-9, 2)  #=> ((36/85)-(77/85)*i)
00849  *    Complex(9, 8)  / 4               #=> ((9/4)+(2/1)*i)
00850  *    Complex(20, 9) / 9.8             #=> (2.0408163265306123+0.9183673469387754i)
00851  */
00852 static VALUE
00853 nucomp_div(VALUE self, VALUE other)
00854 {
00855     return f_divide(self, other, f_quo, id_quo);
00856 }
00857 
00858 #define nucomp_quo nucomp_div
00859 
00860 /*
00861  * call-seq:
00862  *    cmp.fdiv(numeric)  ->  complex
00863  *
00864  * Performs division as each part is a float, never returns a float.
00865  *
00866  *    Complex(11, 22).fdiv(3)  #=> (3.6666666666666665+7.333333333333333i)
00867  */
00868 static VALUE
00869 nucomp_fdiv(VALUE self, VALUE other)
00870 {
00871     return f_divide(self, other, f_fdiv, id_fdiv);
00872 }
00873 
00874 inline static VALUE
00875 f_reciprocal(VALUE x)
00876 {
00877     return f_quo(ONE, x);
00878 }
00879 
00880 /*
00881  * call-seq:
00882  *    cmp ** numeric  ->  complex
00883  *
00884  * Performs exponentiation.
00885  *
00886  *    Complex('i') ** 2              #=> (-1+0i)
00887  *    Complex(-8) ** Rational(1, 3)  #=> (1.0000000000000002+1.7320508075688772i)
00888  */
00889 static VALUE
00890 nucomp_expt(VALUE self, VALUE other)
00891 {
00892     if (k_numeric_p(other) && k_exact_zero_p(other))
00893         return f_complex_new_bang1(CLASS_OF(self), ONE);
00894 
00895     if (k_rational_p(other) && f_one_p(f_denominator(other)))
00896         other = f_numerator(other); /* c14n */
00897 
00898     if (k_complex_p(other)) {
00899         get_dat1(other);
00900 
00901         if (k_exact_zero_p(dat->imag))
00902             other = dat->real; /* c14n */
00903     }
00904 
00905     if (k_complex_p(other)) {
00906         VALUE r, theta, nr, ntheta;
00907 
00908         get_dat1(other);
00909 
00910         r = f_abs(self);
00911         theta = f_arg(self);
00912 
00913         nr = m_exp_bang(f_sub(f_mul(dat->real, m_log_bang(r)),
00914                               f_mul(dat->imag, theta)));
00915         ntheta = f_add(f_mul(theta, dat->real),
00916                        f_mul(dat->imag, m_log_bang(r)));
00917         return f_complex_polar(CLASS_OF(self), nr, ntheta);
00918     }
00919     if (k_fixnum_p(other)) {
00920         if (f_gt_p(other, ZERO)) {
00921             VALUE x, z;
00922             long n;
00923 
00924             x = self;
00925             z = x;
00926             n = FIX2LONG(other) - 1;
00927 
00928             while (n) {
00929                 long q, r;
00930 
00931                 while (1) {
00932                     get_dat1(x);
00933 
00934                     q = n / 2;
00935                     r = n % 2;
00936 
00937                     if (r)
00938                         break;
00939 
00940                     x = nucomp_s_new_internal(CLASS_OF(self),
00941                                        f_sub(f_mul(dat->real, dat->real),
00942                                              f_mul(dat->imag, dat->imag)),
00943                                        f_mul(f_mul(TWO, dat->real), dat->imag));
00944                     n = q;
00945                 }
00946                 z = f_mul(z, x);
00947                 n--;
00948             }
00949             return z;
00950         }
00951         return f_expt(f_reciprocal(self), f_negate(other));
00952     }
00953     if (k_numeric_p(other) && f_real_p(other)) {
00954         VALUE r, theta;
00955 
00956         if (k_bignum_p(other))
00957             rb_warn("in a**b, b may be too big");
00958 
00959         r = f_abs(self);
00960         theta = f_arg(self);
00961 
00962         return f_complex_polar(CLASS_OF(self), f_expt(r, other),
00963                                f_mul(theta, other));
00964     }
00965     return rb_num_coerce_bin(self, other, id_expt);
00966 }
00967 
00968 /*
00969  * call-seq:
00970  *    cmp == object  ->  true or false
00971  *
00972  * Returns true if cmp equals object numerically.
00973  *
00974  *    Complex(2, 3)  == Complex(2, 3)   #=> true
00975  *    Complex(5)     == 5               #=> true
00976  *    Complex(0)     == 0.0             #=> true
00977  *    Complex('1/3') == 0.33            #=> false
00978  *    Complex('1/2') == '1/2'           #=> false
00979  */
00980 static VALUE
00981 nucomp_eqeq_p(VALUE self, VALUE other)
00982 {
00983     if (k_complex_p(other)) {
00984         get_dat2(self, other);
00985 
00986         return f_boolcast(f_eqeq_p(adat->real, bdat->real) &&
00987                           f_eqeq_p(adat->imag, bdat->imag));
00988     }
00989     if (k_numeric_p(other) && f_real_p(other)) {
00990         get_dat1(self);
00991 
00992         return f_boolcast(f_eqeq_p(dat->real, other) && f_zero_p(dat->imag));
00993     }
00994     return f_eqeq_p(other, self);
00995 }
00996 
00997 /* :nodoc: */
00998 static VALUE
00999 nucomp_coerce(VALUE self, VALUE other)
01000 {
01001     if (k_numeric_p(other) && f_real_p(other))
01002         return rb_assoc_new(f_complex_new_bang1(CLASS_OF(self), other), self);
01003     if (RB_TYPE_P(other, T_COMPLEX))
01004         return rb_assoc_new(other, self);
01005 
01006     rb_raise(rb_eTypeError, "%s can't be coerced into %s",
01007              rb_obj_classname(other), rb_obj_classname(self));
01008     return Qnil;
01009 }
01010 
01011 /*
01012  * call-seq:
01013  *    cmp.abs        ->  real
01014  *    cmp.magnitude  ->  real
01015  *
01016  * Returns the absolute part of its polar form.
01017  *
01018  *    Complex(-1).abs         #=> 1
01019  *    Complex(3.0, -4.0).abs  #=> 5.0
01020  */
01021 static VALUE
01022 nucomp_abs(VALUE self)
01023 {
01024     get_dat1(self);
01025 
01026     if (f_zero_p(dat->real)) {
01027         VALUE a = f_abs(dat->imag);
01028         if (k_float_p(dat->real) && !k_float_p(dat->imag))
01029             a = f_to_f(a);
01030         return a;
01031     }
01032     if (f_zero_p(dat->imag)) {
01033         VALUE a = f_abs(dat->real);
01034         if (!k_float_p(dat->real) && k_float_p(dat->imag))
01035             a = f_to_f(a);
01036         return a;
01037     }
01038     return m_hypot(dat->real, dat->imag);
01039 }
01040 
01041 /*
01042  * call-seq:
01043  *    cmp.abs2  ->  real
01044  *
01045  * Returns square of the absolute value.
01046  *
01047  *    Complex(-1).abs2         #=> 1
01048  *    Complex(3.0, -4.0).abs2  #=> 25.0
01049  */
01050 static VALUE
01051 nucomp_abs2(VALUE self)
01052 {
01053     get_dat1(self);
01054     return f_add(f_mul(dat->real, dat->real),
01055                  f_mul(dat->imag, dat->imag));
01056 }
01057 
01058 /*
01059  * call-seq:
01060  *    cmp.arg    ->  float
01061  *    cmp.angle  ->  float
01062  *    cmp.phase  ->  float
01063  *
01064  * Returns the angle part of its polar form.
01065  *
01066  *    Complex.polar(3, Math::PI/2).arg  #=> 1.5707963267948966
01067  */
01068 static VALUE
01069 nucomp_arg(VALUE self)
01070 {
01071     get_dat1(self);
01072     return m_atan2_bang(dat->imag, dat->real);
01073 }
01074 
01075 /*
01076  * call-seq:
01077  *    cmp.rect         ->  array
01078  *    cmp.rectangular  ->  array
01079  *
01080  * Returns an array; [cmp.real, cmp.imag].
01081  *
01082  *    Complex(1, 2).rectangular  #=> [1, 2]
01083  */
01084 static VALUE
01085 nucomp_rect(VALUE self)
01086 {
01087     get_dat1(self);
01088     return rb_assoc_new(dat->real, dat->imag);
01089 }
01090 
01091 /*
01092  * call-seq:
01093  *    cmp.polar  ->  array
01094  *
01095  * Returns an array; [cmp.abs, cmp.arg].
01096  *
01097  *    Complex(1, 2).polar  #=> [2.23606797749979, 1.1071487177940904]
01098  */
01099 static VALUE
01100 nucomp_polar(VALUE self)
01101 {
01102     return rb_assoc_new(f_abs(self), f_arg(self));
01103 }
01104 
01105 /*
01106  * call-seq:
01107  *    cmp.conj       ->  complex
01108  *    cmp.conjugate  ->  complex
01109  *
01110  * Returns the complex conjugate.
01111  *
01112  *    Complex(1, 2).conjugate  #=> (1-2i)
01113  */
01114 static VALUE
01115 nucomp_conj(VALUE self)
01116 {
01117     get_dat1(self);
01118     return f_complex_new2(CLASS_OF(self), dat->real, f_negate(dat->imag));
01119 }
01120 
01121 #if 0
01122 /* :nodoc: */
01123 static VALUE
01124 nucomp_true(VALUE self)
01125 {
01126     return Qtrue;
01127 }
01128 #endif
01129 
01130 /*
01131  * call-seq:
01132  *    cmp.real?  ->  false
01133  *
01134  * Returns false.
01135  */
01136 static VALUE
01137 nucomp_false(VALUE self)
01138 {
01139     return Qfalse;
01140 }
01141 
01142 #if 0
01143 /* :nodoc: */
01144 static VALUE
01145 nucomp_exact_p(VALUE self)
01146 {
01147     get_dat1(self);
01148     return f_boolcast(k_exact_p(dat->real) && k_exact_p(dat->imag));
01149 }
01150 
01151 /* :nodoc: */
01152 static VALUE
01153 nucomp_inexact_p(VALUE self)
01154 {
01155     return f_boolcast(!nucomp_exact_p(self));
01156 }
01157 #endif
01158 
01159 /*
01160  * call-seq:
01161  *    cmp.denominator  ->  integer
01162  *
01163  * Returns the denominator (lcm of both denominator - real and imag).
01164  *
01165  * See numerator.
01166  */
01167 static VALUE
01168 nucomp_denominator(VALUE self)
01169 {
01170     get_dat1(self);
01171     return rb_lcm(f_denominator(dat->real), f_denominator(dat->imag));
01172 }
01173 
01174 /*
01175  * call-seq:
01176  *    cmp.numerator  ->  numeric
01177  *
01178  * Returns the numerator.
01179  *
01180  *        1   2       3+4i  <-  numerator
01181  *        - + -i  ->  ----
01182  *        2   3        6    <-  denominator
01183  *
01184  *    c = Complex('1/2+2/3i')  #=> ((1/2)+(2/3)*i)
01185  *    n = c.numerator          #=> (3+4i)
01186  *    d = c.denominator        #=> 6
01187  *    n / d                    #=> ((1/2)+(2/3)*i)
01188  *    Complex(Rational(n.real, d), Rational(n.imag, d))
01189  *                             #=> ((1/2)+(2/3)*i)
01190  * See denominator.
01191  */
01192 static VALUE
01193 nucomp_numerator(VALUE self)
01194 {
01195     VALUE cd;
01196 
01197     get_dat1(self);
01198 
01199     cd = f_denominator(self);
01200     return f_complex_new2(CLASS_OF(self),
01201                           f_mul(f_numerator(dat->real),
01202                                 f_div(cd, f_denominator(dat->real))),
01203                           f_mul(f_numerator(dat->imag),
01204                                 f_div(cd, f_denominator(dat->imag))));
01205 }
01206 
01207 /* :nodoc: */
01208 static VALUE
01209 nucomp_hash(VALUE self)
01210 {
01211     st_index_t v, h[2];
01212     VALUE n;
01213 
01214     get_dat1(self);
01215     n = rb_hash(dat->real);
01216     h[0] = NUM2LONG(n);
01217     n = rb_hash(dat->imag);
01218     h[1] = NUM2LONG(n);
01219     v = rb_memhash(h, sizeof(h));
01220     return LONG2FIX(v);
01221 }
01222 
01223 /* :nodoc: */
01224 static VALUE
01225 nucomp_eql_p(VALUE self, VALUE other)
01226 {
01227     if (k_complex_p(other)) {
01228         get_dat2(self, other);
01229 
01230         return f_boolcast((CLASS_OF(adat->real) == CLASS_OF(bdat->real)) &&
01231                           (CLASS_OF(adat->imag) == CLASS_OF(bdat->imag)) &&
01232                           f_eqeq_p(self, other));
01233 
01234     }
01235     return Qfalse;
01236 }
01237 
01238 inline static VALUE
01239 f_signbit(VALUE x)
01240 {
01241 #if defined(HAVE_SIGNBIT) && defined(__GNUC__) && defined(__sun) && \
01242     !defined(signbit)
01243     extern int signbit(double);
01244 #endif
01245     switch (TYPE(x)) {
01246       case T_FLOAT: {
01247         double f = RFLOAT_VALUE(x);
01248         return f_boolcast(!isnan(f) && signbit(f));
01249       }
01250     }
01251     return f_negative_p(x);
01252 }
01253 
01254 inline static VALUE
01255 f_tpositive_p(VALUE x)
01256 {
01257     return f_boolcast(!f_signbit(x));
01258 }
01259 
01260 static VALUE
01261 f_format(VALUE self, VALUE (*func)(VALUE))
01262 {
01263     VALUE s, impos;
01264 
01265     get_dat1(self);
01266 
01267     impos = f_tpositive_p(dat->imag);
01268 
01269     s = (*func)(dat->real);
01270     rb_str_cat2(s, !impos ? "-" : "+");
01271 
01272     rb_str_concat(s, (*func)(f_abs(dat->imag)));
01273     if (!rb_isdigit(RSTRING_PTR(s)[RSTRING_LEN(s) - 1]))
01274         rb_str_cat2(s, "*");
01275     rb_str_cat2(s, "i");
01276 
01277     return s;
01278 }
01279 
01280 /*
01281  * call-seq:
01282  *    cmp.to_s  ->  string
01283  *
01284  * Returns the value as a string.
01285  *
01286  *    Complex(2).to_s                       #=> "2+0i"
01287  *    Complex('-8/6').to_s                  #=> "-4/3+0i"
01288  *    Complex('1/2i').to_s                  #=> "0+1/2i"
01289  *    Complex(0, Float::INFINITY).to_s      #=> "0+Infinity*i"
01290  *    Complex(Float::NAN, Float::NAN).to_s  #=> "NaN+NaN*i"
01291  */
01292 static VALUE
01293 nucomp_to_s(VALUE self)
01294 {
01295     return f_format(self, f_to_s);
01296 }
01297 
01298 /*
01299  * call-seq:
01300  *    cmp.inspect  ->  string
01301  *
01302  * Returns the value as a string for inspection.
01303  *
01304  *    Complex(2).inspect                       #=> "(2+0i)"
01305  *    Complex('-8/6').inspect                  #=> "((-4/3)+0i)"
01306  *    Complex('1/2i').inspect                  #=> "(0+(1/2)*i)"
01307  *    Complex(0, Float::INFINITY).inspect      #=> "(0+Infinity*i)"
01308  *    Complex(Float::NAN, Float::NAN).inspect  #=> "(NaN+NaN*i)"
01309  */
01310 static VALUE
01311 nucomp_inspect(VALUE self)
01312 {
01313     VALUE s;
01314 
01315     s = rb_usascii_str_new2("(");
01316     rb_str_concat(s, f_format(self, f_inspect));
01317     rb_str_cat2(s, ")");
01318 
01319     return s;
01320 }
01321 
01322 /* :nodoc: */
01323 static VALUE
01324 nucomp_dumper(VALUE self)
01325 {
01326     return self;
01327 }
01328 
01329 /* :nodoc: */
01330 static VALUE
01331 nucomp_loader(VALUE self, VALUE a)
01332 {
01333     get_dat1(self);
01334 
01335     dat->real = rb_ivar_get(a, id_i_real);
01336     dat->imag = rb_ivar_get(a, id_i_imag);
01337 
01338     return self;
01339 }
01340 
01341 /* :nodoc: */
01342 static VALUE
01343 nucomp_marshal_dump(VALUE self)
01344 {
01345     VALUE a;
01346     get_dat1(self);
01347 
01348     a = rb_assoc_new(dat->real, dat->imag);
01349     rb_copy_generic_ivar(a, self);
01350     return a;
01351 }
01352 
01353 /* :nodoc: */
01354 static VALUE
01355 nucomp_marshal_load(VALUE self, VALUE a)
01356 {
01357     Check_Type(a, T_ARRAY);
01358     if (RARRAY_LEN(a) != 2)
01359         rb_raise(rb_eArgError, "marshaled complex must have an array whose length is 2 but %ld", RARRAY_LEN(a));
01360     rb_ivar_set(self, id_i_real, RARRAY_PTR(a)[0]);
01361     rb_ivar_set(self, id_i_imag, RARRAY_PTR(a)[1]);
01362     return self;
01363 }
01364 
01365 /* --- */
01366 
01367 VALUE
01368 rb_complex_raw(VALUE x, VALUE y)
01369 {
01370     return nucomp_s_new_internal(rb_cComplex, x, y);
01371 }
01372 
01373 VALUE
01374 rb_complex_new(VALUE x, VALUE y)
01375 {
01376     return nucomp_s_canonicalize_internal(rb_cComplex, x, y);
01377 }
01378 
01379 VALUE
01380 rb_complex_polar(VALUE x, VALUE y)
01381 {
01382     return f_complex_polar(rb_cComplex, x, y);
01383 }
01384 
01385 static VALUE nucomp_s_convert(int argc, VALUE *argv, VALUE klass);
01386 
01387 VALUE
01388 rb_Complex(VALUE x, VALUE y)
01389 {
01390     VALUE a[2];
01391     a[0] = x;
01392     a[1] = y;
01393     return nucomp_s_convert(2, a, rb_cComplex);
01394 }
01395 
01396 /*
01397  * call-seq:
01398  *    cmp.to_i  ->  integer
01399  *
01400  * Returns the value as an integer if possible (the imaginary part
01401  * should be exactly zero).
01402  *
01403  *    Complex(1, 0).to_i    #=> 1
01404  *    Complex(1, 0.0).to_i  # RangeError
01405  *    Complex(1, 2).to_i    # RangeError
01406  */
01407 static VALUE
01408 nucomp_to_i(VALUE self)
01409 {
01410     get_dat1(self);
01411 
01412     if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) {
01413         VALUE s = f_to_s(self);
01414         rb_raise(rb_eRangeError, "can't convert %s into Integer",
01415                  StringValuePtr(s));
01416     }
01417     return f_to_i(dat->real);
01418 }
01419 
01420 /*
01421  * call-seq:
01422  *    cmp.to_f  ->  float
01423  *
01424  * Returns the value as a float if possible (the imaginary part should
01425  * be exactly zero).
01426  *
01427  *    Complex(1, 0).to_f    #=> 1.0
01428  *    Complex(1, 0.0).to_f  # RangeError
01429  *    Complex(1, 2).to_f    # RangeError
01430  */
01431 static VALUE
01432 nucomp_to_f(VALUE self)
01433 {
01434     get_dat1(self);
01435 
01436     if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) {
01437         VALUE s = f_to_s(self);
01438         rb_raise(rb_eRangeError, "can't convert %s into Float",
01439                  StringValuePtr(s));
01440     }
01441     return f_to_f(dat->real);
01442 }
01443 
01444 /*
01445  * call-seq:
01446  *    cmp.to_r  ->  rational
01447  *
01448  * Returns the value as a rational if possible (the imaginary part
01449  * should be exactly zero).
01450  *
01451  *    Complex(1, 0).to_r    #=> (1/1)
01452  *    Complex(1, 0.0).to_r  # RangeError
01453  *    Complex(1, 2).to_r    # RangeError
01454  *
01455  * See rationalize.
01456  */
01457 static VALUE
01458 nucomp_to_r(VALUE self)
01459 {
01460     get_dat1(self);
01461 
01462     if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) {
01463         VALUE s = f_to_s(self);
01464         rb_raise(rb_eRangeError, "can't convert %s into Rational",
01465                  StringValuePtr(s));
01466     }
01467     return f_to_r(dat->real);
01468 }
01469 
01470 /*
01471  * call-seq:
01472  *    cmp.rationalize([eps])  ->  rational
01473  *
01474  * Returns the value as a rational if possible (the imaginary part
01475  * should be exactly zero).
01476  *
01477  *    Complex(1.0/3, 0).rationalize  #=> (1/3)
01478  *    Complex(1, 0.0).rationalize    # RangeError
01479  *    Complex(1, 2).rationalize      # RangeError
01480  *
01481  * See to_r.
01482  */
01483 static VALUE
01484 nucomp_rationalize(int argc, VALUE *argv, VALUE self)
01485 {
01486     get_dat1(self);
01487 
01488     rb_scan_args(argc, argv, "01", NULL);
01489 
01490     if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) {
01491        VALUE s = f_to_s(self);
01492        rb_raise(rb_eRangeError, "can't convert %s into Rational",
01493                 StringValuePtr(s));
01494     }
01495     return rb_funcall2(dat->real, rb_intern("rationalize"), argc, argv);
01496 }
01497 
01498 /*
01499  * call-seq:
01500  *    complex.to_c  ->  self
01501  *
01502  * Returns self.
01503  *
01504  *    Complex(2).to_c      #=> (2+0i)
01505  *    Complex(-8, 6).to_c  #=> (-8+6i)
01506  */
01507 static VALUE
01508 nucomp_to_c(VALUE self)
01509 {
01510     return self;
01511 }
01512 
01513 /*
01514  * call-seq:
01515  *    nil.to_c  ->  (0+0i)
01516  *
01517  * Returns zero as a complex.
01518  */
01519 static VALUE
01520 nilclass_to_c(VALUE self)
01521 {
01522     return rb_complex_new1(INT2FIX(0));
01523 }
01524 
01525 /*
01526  * call-seq:
01527  *    num.to_c  ->  complex
01528  *
01529  * Returns the value as a complex.
01530  */
01531 static VALUE
01532 numeric_to_c(VALUE self)
01533 {
01534     return rb_complex_new1(self);
01535 }
01536 
01537 #include <ctype.h>
01538 
01539 inline static int
01540 issign(int c)
01541 {
01542     return (c == '-' || c == '+');
01543 }
01544 
01545 static int
01546 read_sign(const char **s,
01547           char **b)
01548 {
01549     int sign = '?';
01550 
01551     if (issign(**s)) {
01552         sign = **b = **s;
01553         (*s)++;
01554         (*b)++;
01555     }
01556     return sign;
01557 }
01558 
01559 inline static int
01560 isdecimal(int c)
01561 {
01562     return isdigit((unsigned char)c);
01563 }
01564 
01565 static int
01566 read_digits(const char **s, int strict,
01567             char **b)
01568 {
01569     int us = 1;
01570 
01571     if (!isdecimal(**s))
01572         return 0;
01573 
01574     while (isdecimal(**s) || **s == '_') {
01575         if (**s == '_') {
01576             if (strict) {
01577                 if (us)
01578                     return 0;
01579             }
01580             us = 1;
01581         }
01582         else {
01583             **b = **s;
01584             (*b)++;
01585             us = 0;
01586         }
01587         (*s)++;
01588     }
01589     if (us)
01590         do {
01591             (*s)--;
01592         } while (**s == '_');
01593     return 1;
01594 }
01595 
01596 inline static int
01597 islettere(int c)
01598 {
01599     return (c == 'e' || c == 'E');
01600 }
01601 
01602 static int
01603 read_num(const char **s, int strict,
01604          char **b)
01605 {
01606     if (**s != '.') {
01607         if (!read_digits(s, strict, b))
01608             return 0;
01609     }
01610 
01611     if (**s == '.') {
01612         **b = **s;
01613         (*s)++;
01614         (*b)++;
01615         if (!read_digits(s, strict, b)) {
01616             (*b)--;
01617             return 0;
01618         }
01619     }
01620 
01621     if (islettere(**s)) {
01622         **b = **s;
01623         (*s)++;
01624         (*b)++;
01625         read_sign(s, b);
01626         if (!read_digits(s, strict, b)) {
01627             (*b)--;
01628             return 0;
01629         }
01630     }
01631     return 1;
01632 }
01633 
01634 inline static int
01635 read_den(const char **s, int strict,
01636          char **b)
01637 {
01638     if (!read_digits(s, strict, b))
01639         return 0;
01640     return 1;
01641 }
01642 
01643 static int
01644 read_rat_nos(const char **s, int strict,
01645              char **b)
01646 {
01647     if (!read_num(s, strict, b))
01648         return 0;
01649     if (**s == '/') {
01650         **b = **s;
01651         (*s)++;
01652         (*b)++;
01653         if (!read_den(s, strict, b)) {
01654             (*b)--;
01655             return 0;
01656         }
01657     }
01658     return 1;
01659 }
01660 
01661 static int
01662 read_rat(const char **s, int strict,
01663          char **b)
01664 {
01665     read_sign(s, b);
01666     if (!read_rat_nos(s, strict, b))
01667         return 0;
01668     return 1;
01669 }
01670 
01671 inline static int
01672 isimagunit(int c)
01673 {
01674     return (c == 'i' || c == 'I' ||
01675             c == 'j' || c == 'J');
01676 }
01677 
01678 VALUE rb_cstr_to_rat(const char *, int);
01679 
01680 static VALUE
01681 str2num(char *s)
01682 {
01683     if (strchr(s, '/'))
01684         return rb_cstr_to_rat(s, 0);
01685     if (strpbrk(s, ".eE"))
01686         return DBL2NUM(rb_cstr_to_dbl(s, 0));
01687     return rb_cstr_to_inum(s, 10, 0);
01688 }
01689 
01690 static int
01691 read_comp(const char **s, int strict,
01692           VALUE *ret, char **b)
01693 {
01694     char *bb;
01695     int sign;
01696     VALUE num, num2;
01697 
01698     bb = *b;
01699 
01700     sign = read_sign(s, b);
01701 
01702     if (isimagunit(**s)) {
01703         (*s)++;
01704         num = INT2FIX((sign == '-') ? -1 : + 1);
01705         *ret = rb_complex_new2(ZERO, num);
01706         return 1; /* e.g. "i" */
01707     }
01708 
01709     if (!read_rat_nos(s, strict, b)) {
01710         **b = '\0';
01711         num = str2num(bb);
01712         *ret = rb_complex_new2(num, ZERO);
01713         return 0; /* e.g. "-" */
01714     }
01715     **b = '\0';
01716     num = str2num(bb);
01717 
01718     if (isimagunit(**s)) {
01719         (*s)++;
01720         *ret = rb_complex_new2(ZERO, num);
01721         return 1; /* e.g. "3i" */
01722     }
01723 
01724     if (**s == '@') {
01725         int st;
01726 
01727         (*s)++;
01728         bb = *b;
01729         st = read_rat(s, strict, b);
01730         **b = '\0';
01731         if (strlen(bb) < 1 ||
01732             !isdecimal(*(bb + strlen(bb) - 1))) {
01733             *ret = rb_complex_new2(num, ZERO);
01734             return 0; /* e.g. "1@-" */
01735         }
01736         num2 = str2num(bb);
01737         *ret = rb_complex_polar(num, num2);
01738         if (!st)
01739             return 0; /* e.g. "1@2." */
01740         else
01741             return 1; /* e.g. "1@2" */
01742     }
01743 
01744     if (issign(**s)) {
01745         bb = *b;
01746         sign = read_sign(s, b);
01747         if (isimagunit(**s))
01748             num2 = INT2FIX((sign == '-') ? -1 : + 1);
01749         else {
01750             if (!read_rat_nos(s, strict, b)) {
01751                 *ret = rb_complex_new2(num, ZERO);
01752                 return 0; /* e.g. "1+xi" */
01753             }
01754             **b = '\0';
01755             num2 = str2num(bb);
01756         }
01757         if (!isimagunit(**s)) {
01758             *ret = rb_complex_new2(num, ZERO);
01759             return 0; /* e.g. "1+3x" */
01760         }
01761         (*s)++;
01762         *ret = rb_complex_new2(num, num2);
01763         return 1; /* e.g. "1+2i" */
01764     }
01765     /* !(@, - or +) */
01766     {
01767         *ret = rb_complex_new2(num, ZERO);
01768         return 1; /* e.g. "3" */
01769     }
01770 }
01771 
01772 inline static void
01773 skip_ws(const char **s)
01774 {
01775     while (isspace((unsigned char)**s))
01776         (*s)++;
01777 }
01778 
01779 static int
01780 parse_comp(const char *s, int strict,
01781            VALUE *num)
01782 {
01783     char *buf, *b;
01784 
01785     buf = ALLOCA_N(char, strlen(s) + 1);
01786     b = buf;
01787 
01788     skip_ws(&s);
01789     if (!read_comp(&s, strict, num, &b))
01790         return 0;
01791     skip_ws(&s);
01792 
01793     if (strict)
01794         if (*s != '\0')
01795             return 0;
01796     return 1;
01797 }
01798 
01799 static VALUE
01800 string_to_c_strict(VALUE self)
01801 {
01802     char *s;
01803     VALUE num;
01804 
01805     rb_must_asciicompat(self);
01806 
01807     s = RSTRING_PTR(self);
01808 
01809     if (!s || memchr(s, '\0', RSTRING_LEN(self)))
01810         rb_raise(rb_eArgError, "string contains null byte");
01811 
01812     if (s && s[RSTRING_LEN(self)]) {
01813         rb_str_modify(self);
01814         s = RSTRING_PTR(self);
01815         s[RSTRING_LEN(self)] = '\0';
01816     }
01817 
01818     if (!s)
01819         s = (char *)"";
01820 
01821     if (!parse_comp(s, 1, &num)) {
01822         VALUE ins = f_inspect(self);
01823         rb_raise(rb_eArgError, "invalid value for convert(): %s",
01824                  StringValuePtr(ins));
01825     }
01826 
01827     return num;
01828 }
01829 
01830 /*
01831  * call-seq:
01832  *    str.to_c  ->  complex
01833  *
01834  * Returns a complex which denotes the string form.  The parser
01835  * ignores leading whitespaces and trailing garbage.  Any digit
01836  * sequences can be separated by an underscore.  Returns zero for null
01837  * or garbage string.
01838  *
01839  *    '9'.to_c           #=> (9+0i)
01840  *    '2.5'.to_c         #=> (2.5+0i)
01841  *    '2.5/1'.to_c       #=> ((5/2)+0i)
01842  *    '-3/2'.to_c        #=> ((-3/2)+0i)
01843  *    '-i'.to_c          #=> (0-1i)
01844  *    '45i'.to_c         #=> (0+45i)
01845  *    '3-4i'.to_c        #=> (3-4i)
01846  *    '-4e2-4e-2i'.to_c  #=> (-400.0-0.04i)
01847  *    '-0.0-0.0i'.to_c   #=> (-0.0-0.0i)
01848  *    '1/2+3/4i'.to_c    #=> ((1/2)+(3/4)*i)
01849  *    'ruby'.to_c        #=> (0+0i)
01850  *
01851  * See Kernel.Complex.
01852  */
01853 static VALUE
01854 string_to_c(VALUE self)
01855 {
01856     char *s;
01857     VALUE num;
01858 
01859     rb_must_asciicompat(self);
01860 
01861     s = RSTRING_PTR(self);
01862 
01863     if (s && s[RSTRING_LEN(self)]) {
01864         rb_str_modify(self);
01865         s = RSTRING_PTR(self);
01866         s[RSTRING_LEN(self)] = '\0';
01867     }
01868 
01869     if (!s)
01870         s = (char *)"";
01871 
01872     (void)parse_comp(s, 0, &num);
01873 
01874     return num;
01875 }
01876 
01877 static VALUE
01878 nucomp_s_convert(int argc, VALUE *argv, VALUE klass)
01879 {
01880     VALUE a1, a2, backref;
01881 
01882     rb_scan_args(argc, argv, "11", &a1, &a2);
01883 
01884     if (NIL_P(a1) || (argc == 2 && NIL_P(a2)))
01885         rb_raise(rb_eTypeError, "can't convert nil into Complex");
01886 
01887     backref = rb_backref_get();
01888     rb_match_busy(backref);
01889 
01890     switch (TYPE(a1)) {
01891       case T_FIXNUM:
01892       case T_BIGNUM:
01893       case T_FLOAT:
01894         break;
01895       case T_STRING:
01896         a1 = string_to_c_strict(a1);
01897         break;
01898     }
01899 
01900     switch (TYPE(a2)) {
01901       case T_FIXNUM:
01902       case T_BIGNUM:
01903       case T_FLOAT:
01904         break;
01905       case T_STRING:
01906         a2 = string_to_c_strict(a2);
01907         break;
01908     }
01909 
01910     rb_backref_set(backref);
01911 
01912     switch (TYPE(a1)) {
01913       case T_COMPLEX:
01914         {
01915             get_dat1(a1);
01916 
01917             if (k_exact_zero_p(dat->imag))
01918                 a1 = dat->real;
01919         }
01920     }
01921 
01922     switch (TYPE(a2)) {
01923       case T_COMPLEX:
01924         {
01925             get_dat1(a2);
01926 
01927             if (k_exact_zero_p(dat->imag))
01928                 a2 = dat->real;
01929         }
01930     }
01931 
01932     switch (TYPE(a1)) {
01933       case T_COMPLEX:
01934         if (argc == 1 || (k_exact_zero_p(a2)))
01935             return a1;
01936     }
01937 
01938     if (argc == 1) {
01939         if (k_numeric_p(a1) && !f_real_p(a1))
01940             return a1;
01941         /* should raise exception for consistency */
01942         if (!k_numeric_p(a1))
01943             return rb_convert_type(a1, T_COMPLEX, "Complex", "to_c");
01944     }
01945     else {
01946         if ((k_numeric_p(a1) && k_numeric_p(a2)) &&
01947             (!f_real_p(a1) || !f_real_p(a2)))
01948             return f_add(a1,
01949                          f_mul(a2,
01950                                f_complex_new_bang2(rb_cComplex, ZERO, ONE)));
01951     }
01952 
01953     {
01954         VALUE argv2[2];
01955         argv2[0] = a1;
01956         argv2[1] = a2;
01957         return nucomp_s_new(argc, argv2, klass);
01958     }
01959 }
01960 
01961 /* --- */
01962 
01963 /*
01964  * call-seq:
01965  *    num.real  ->  self
01966  *
01967  * Returns self.
01968  */
01969 static VALUE
01970 numeric_real(VALUE self)
01971 {
01972     return self;
01973 }
01974 
01975 /*
01976  * call-seq:
01977  *    num.imag       ->  0
01978  *    num.imaginary  ->  0
01979  *
01980  * Returns zero.
01981  */
01982 static VALUE
01983 numeric_imag(VALUE self)
01984 {
01985     return INT2FIX(0);
01986 }
01987 
01988 /*
01989  * call-seq:
01990  *    num.abs2  ->  real
01991  *
01992  * Returns square of self.
01993  */
01994 static VALUE
01995 numeric_abs2(VALUE self)
01996 {
01997     return f_mul(self, self);
01998 }
01999 
02000 #define id_PI rb_intern("PI")
02001 
02002 /*
02003  * call-seq:
02004  *    num.arg    ->  0 or float
02005  *    num.angle  ->  0 or float
02006  *    num.phase  ->  0 or float
02007  *
02008  * Returns 0 if the value is positive, pi otherwise.
02009  */
02010 static VALUE
02011 numeric_arg(VALUE self)
02012 {
02013     if (f_positive_p(self))
02014         return INT2FIX(0);
02015     return rb_const_get(rb_mMath, id_PI);
02016 }
02017 
02018 /*
02019  * call-seq:
02020  *    num.rect  ->  array
02021  *
02022  * Returns an array; [num, 0].
02023  */
02024 static VALUE
02025 numeric_rect(VALUE self)
02026 {
02027     return rb_assoc_new(self, INT2FIX(0));
02028 }
02029 
02030 /*
02031  * call-seq:
02032  *    num.polar  ->  array
02033  *
02034  * Returns an array; [num.abs, num.arg].
02035  */
02036 static VALUE
02037 numeric_polar(VALUE self)
02038 {
02039     return rb_assoc_new(f_abs(self), f_arg(self));
02040 }
02041 
02042 /*
02043  * call-seq:
02044  *    num.conj       ->  self
02045  *    num.conjugate  ->  self
02046  *
02047  * Returns self.
02048  */
02049 static VALUE
02050 numeric_conj(VALUE self)
02051 {
02052     return self;
02053 }
02054 
02055 /*
02056  * call-seq:
02057  *    flo.arg    ->  0 or float
02058  *    flo.angle  ->  0 or float
02059  *    flo.phase  ->  0 or float
02060  *
02061  * Returns 0 if the value is positive, pi otherwise.
02062  */
02063 static VALUE
02064 float_arg(VALUE self)
02065 {
02066     if (isnan(RFLOAT_VALUE(self)))
02067         return self;
02068     if (f_tpositive_p(self))
02069         return INT2FIX(0);
02070     return rb_const_get(rb_mMath, id_PI);
02071 }
02072 
02073 /*
02074  * A complex number can be represented as a paired real number with
02075  * imaginary unit; a+bi.  Where a is real part, b is imaginary part
02076  * and i is imaginary unit.  Real a equals complex a+0i
02077  * mathematically.
02078  *
02079  * In ruby, you can create complex object with Complex, Complex::rect,
02080  * Complex::polar or to_c method.
02081  *
02082  *    Complex(1)           #=> (1+0i)
02083  *    Complex(2, 3)        #=> (2+3i)
02084  *    Complex.polar(2, 3)  #=> (-1.9799849932008908+0.2822400161197344i)
02085  *    3.to_c               #=> (3+0i)
02086  *
02087  * You can also create complex object from floating-point numbers or
02088  * strings.
02089  *
02090  *    Complex(0.3)         #=> (0.3+0i)
02091  *    Complex('0.3-0.5i')  #=> (0.3-0.5i)
02092  *    Complex('2/3+3/4i')  #=> ((2/3)+(3/4)*i)
02093  *    Complex('1@2')       #=> (-0.4161468365471424+0.9092974268256817i)
02094  *
02095  *    0.3.to_c             #=> (0.3+0i)
02096  *    '0.3-0.5i'.to_c      #=> (0.3-0.5i)
02097  *    '2/3+3/4i'.to_c      #=> ((2/3)+(3/4)*i)
02098  *    '1@2'.to_c           #=> (-0.4161468365471424+0.9092974268256817i)
02099  *
02100  * A complex object is either an exact or an inexact number.
02101  *
02102  *    Complex(1, 1) / 2    #=> ((1/2)+(1/2)*i)
02103  *    Complex(1, 1) / 2.0  #=> (0.5+0.5i)
02104  */
02105 void
02106 Init_Complex(void)
02107 {
02108     VALUE compat;
02109 #undef rb_intern
02110 #define rb_intern(str) rb_intern_const(str)
02111 
02112     assert(fprintf(stderr, "assert() is now active\n"));
02113 
02114     id_abs = rb_intern("abs");
02115     id_abs2 = rb_intern("abs2");
02116     id_arg = rb_intern("arg");
02117     id_cmp = rb_intern("<=>");
02118     id_conj = rb_intern("conj");
02119     id_convert = rb_intern("convert");
02120     id_denominator = rb_intern("denominator");
02121     id_divmod = rb_intern("divmod");
02122     id_eqeq_p = rb_intern("==");
02123     id_expt = rb_intern("**");
02124     id_fdiv = rb_intern("fdiv");
02125     id_floor = rb_intern("floor");
02126     id_idiv = rb_intern("div");
02127     id_imag = rb_intern("imag");
02128     id_inspect = rb_intern("inspect");
02129     id_negate = rb_intern("-@");
02130     id_numerator = rb_intern("numerator");
02131     id_quo = rb_intern("quo");
02132     id_real = rb_intern("real");
02133     id_real_p = rb_intern("real?");
02134     id_to_f = rb_intern("to_f");
02135     id_to_i = rb_intern("to_i");
02136     id_to_r = rb_intern("to_r");
02137     id_to_s = rb_intern("to_s");
02138     id_i_real = rb_intern("@real");
02139     id_i_imag = rb_intern("@image"); /* @image, not @imag */
02140 
02141     rb_cComplex = rb_define_class("Complex", rb_cNumeric);
02142 
02143     rb_define_alloc_func(rb_cComplex, nucomp_s_alloc);
02144     rb_undef_method(CLASS_OF(rb_cComplex), "allocate");
02145 
02146 #if 0
02147     rb_define_private_method(CLASS_OF(rb_cComplex), "new!", nucomp_s_new_bang, -1);
02148     rb_define_private_method(CLASS_OF(rb_cComplex), "new", nucomp_s_new, -1);
02149 #else
02150     rb_undef_method(CLASS_OF(rb_cComplex), "new");
02151 #endif
02152 
02153     rb_define_singleton_method(rb_cComplex, "rectangular", nucomp_s_new, -1);
02154     rb_define_singleton_method(rb_cComplex, "rect", nucomp_s_new, -1);
02155     rb_define_singleton_method(rb_cComplex, "polar", nucomp_s_polar, -1);
02156 
02157     rb_define_global_function("Complex", nucomp_f_complex, -1);
02158 
02159     rb_undef_method(rb_cComplex, "%");
02160     rb_undef_method(rb_cComplex, "<");
02161     rb_undef_method(rb_cComplex, "<=");
02162     rb_undef_method(rb_cComplex, "<=>");
02163     rb_undef_method(rb_cComplex, ">");
02164     rb_undef_method(rb_cComplex, ">=");
02165     rb_undef_method(rb_cComplex, "between?");
02166     rb_undef_method(rb_cComplex, "div");
02167     rb_undef_method(rb_cComplex, "divmod");
02168     rb_undef_method(rb_cComplex, "floor");
02169     rb_undef_method(rb_cComplex, "ceil");
02170     rb_undef_method(rb_cComplex, "modulo");
02171     rb_undef_method(rb_cComplex, "remainder");
02172     rb_undef_method(rb_cComplex, "round");
02173     rb_undef_method(rb_cComplex, "step");
02174     rb_undef_method(rb_cComplex, "truncate");
02175     rb_undef_method(rb_cComplex, "i");
02176 
02177 #if 0 /* NUBY */
02178     rb_undef_method(rb_cComplex, "//");
02179 #endif
02180 
02181     rb_define_method(rb_cComplex, "real", nucomp_real, 0);
02182     rb_define_method(rb_cComplex, "imaginary", nucomp_imag, 0);
02183     rb_define_method(rb_cComplex, "imag", nucomp_imag, 0);
02184 
02185     rb_define_method(rb_cComplex, "-@", nucomp_negate, 0);
02186     rb_define_method(rb_cComplex, "+", nucomp_add, 1);
02187     rb_define_method(rb_cComplex, "-", nucomp_sub, 1);
02188     rb_define_method(rb_cComplex, "*", nucomp_mul, 1);
02189     rb_define_method(rb_cComplex, "/", nucomp_div, 1);
02190     rb_define_method(rb_cComplex, "quo", nucomp_quo, 1);
02191     rb_define_method(rb_cComplex, "fdiv", nucomp_fdiv, 1);
02192     rb_define_method(rb_cComplex, "**", nucomp_expt, 1);
02193 
02194     rb_define_method(rb_cComplex, "==", nucomp_eqeq_p, 1);
02195     rb_define_method(rb_cComplex, "coerce", nucomp_coerce, 1);
02196 
02197     rb_define_method(rb_cComplex, "abs", nucomp_abs, 0);
02198     rb_define_method(rb_cComplex, "magnitude", nucomp_abs, 0);
02199     rb_define_method(rb_cComplex, "abs2", nucomp_abs2, 0);
02200     rb_define_method(rb_cComplex, "arg", nucomp_arg, 0);
02201     rb_define_method(rb_cComplex, "angle", nucomp_arg, 0);
02202     rb_define_method(rb_cComplex, "phase", nucomp_arg, 0);
02203     rb_define_method(rb_cComplex, "rectangular", nucomp_rect, 0);
02204     rb_define_method(rb_cComplex, "rect", nucomp_rect, 0);
02205     rb_define_method(rb_cComplex, "polar", nucomp_polar, 0);
02206     rb_define_method(rb_cComplex, "conjugate", nucomp_conj, 0);
02207     rb_define_method(rb_cComplex, "conj", nucomp_conj, 0);
02208 #if 0
02209     rb_define_method(rb_cComplex, "~", nucomp_conj, 0); /* gcc */
02210 #endif
02211 
02212     rb_define_method(rb_cComplex, "real?", nucomp_false, 0);
02213 #if 0
02214     rb_define_method(rb_cComplex, "complex?", nucomp_true, 0);
02215     rb_define_method(rb_cComplex, "exact?", nucomp_exact_p, 0);
02216     rb_define_method(rb_cComplex, "inexact?", nucomp_inexact_p, 0);
02217 #endif
02218 
02219     rb_define_method(rb_cComplex, "numerator", nucomp_numerator, 0);
02220     rb_define_method(rb_cComplex, "denominator", nucomp_denominator, 0);
02221 
02222     rb_define_method(rb_cComplex, "hash", nucomp_hash, 0);
02223     rb_define_method(rb_cComplex, "eql?", nucomp_eql_p, 1);
02224 
02225     rb_define_method(rb_cComplex, "to_s", nucomp_to_s, 0);
02226     rb_define_method(rb_cComplex, "inspect", nucomp_inspect, 0);
02227 
02228     rb_define_private_method(rb_cComplex, "marshal_dump", nucomp_marshal_dump, 0);
02229     compat = rb_define_class_under(rb_cComplex, "compatible", rb_cObject);
02230     rb_define_private_method(compat, "marshal_load", nucomp_marshal_load, 1);
02231     rb_marshal_define_compat(rb_cComplex, compat, nucomp_dumper, nucomp_loader);
02232 
02233     /* --- */
02234 
02235     rb_define_method(rb_cComplex, "to_i", nucomp_to_i, 0);
02236     rb_define_method(rb_cComplex, "to_f", nucomp_to_f, 0);
02237     rb_define_method(rb_cComplex, "to_r", nucomp_to_r, 0);
02238     rb_define_method(rb_cComplex, "rationalize", nucomp_rationalize, -1);
02239     rb_define_method(rb_cComplex, "to_c", nucomp_to_c, 0);
02240     rb_define_method(rb_cNilClass, "to_c", nilclass_to_c, 0);
02241     rb_define_method(rb_cNumeric, "to_c", numeric_to_c, 0);
02242 
02243     rb_define_method(rb_cString, "to_c", string_to_c, 0);
02244 
02245     rb_define_private_method(CLASS_OF(rb_cComplex), "convert", nucomp_s_convert, -1);
02246 
02247     /* --- */
02248 
02249     rb_define_method(rb_cNumeric, "real", numeric_real, 0);
02250     rb_define_method(rb_cNumeric, "imaginary", numeric_imag, 0);
02251     rb_define_method(rb_cNumeric, "imag", numeric_imag, 0);
02252     rb_define_method(rb_cNumeric, "abs2", numeric_abs2, 0);
02253     rb_define_method(rb_cNumeric, "arg", numeric_arg, 0);
02254     rb_define_method(rb_cNumeric, "angle", numeric_arg, 0);
02255     rb_define_method(rb_cNumeric, "phase", numeric_arg, 0);
02256     rb_define_method(rb_cNumeric, "rectangular", numeric_rect, 0);
02257     rb_define_method(rb_cNumeric, "rect", numeric_rect, 0);
02258     rb_define_method(rb_cNumeric, "polar", numeric_polar, 0);
02259     rb_define_method(rb_cNumeric, "conjugate", numeric_conj, 0);
02260     rb_define_method(rb_cNumeric, "conj", numeric_conj, 0);
02261 
02262     rb_define_method(rb_cFloat, "arg", float_arg, 0);
02263     rb_define_method(rb_cFloat, "angle", float_arg, 0);
02264     rb_define_method(rb_cFloat, "phase", float_arg, 0);
02265 
02266     /*
02267      * The imaginary unit.
02268      */
02269     rb_define_const(rb_cComplex, "I",
02270                     f_complex_new_bang2(rb_cComplex, ZERO, ONE));
02271 }
02272 
02273 /*
02274 Local variables:
02275 c-file-style: "ruby"
02276 End:
02277 */
02278