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

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7