00001
00002
00003
00004
00005
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
00395
00396
00397
00398
00399
00400
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
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
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
00564
00565
00566
00567
00568
00569
00570
00571
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
00593
00594
00595
00596
00597
00598
00599
00600 static VALUE
00601 nucomp_real(VALUE self)
00602 {
00603 get_dat1(self);
00604 return dat->real;
00605 }
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617 static VALUE
00618 nucomp_imag(VALUE self)
00619 {
00620 get_dat1(self);
00621 return dat->imag;
00622 }
00623
00624
00625
00626
00627
00628
00629
00630
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
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675 static VALUE
00676 nucomp_add(VALUE self, VALUE other)
00677 {
00678 return f_addsub(self, other, f_add, '+');
00679 }
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693 static VALUE
00694 nucomp_sub(VALUE self, VALUE other)
00695 {
00696 return f_addsub(self, other, f_sub, '-');
00697 }
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
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
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
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
00813
00814
00815
00816
00817
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
00833
00834
00835
00836
00837
00838
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);
00848
00849 if (k_complex_p(other)) {
00850 get_dat1(other);
00851
00852 if (k_exact_zero_p(dat->imag))
00853 other = dat->real;
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
00921
00922
00923
00924
00925
00926
00927
00928
00929
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
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
00964
00965
00966
00967
00968
00969
00970
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
00994
00995
00996
00997
00998
00999
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
01011
01012
01013
01014
01015
01016
01017
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
01028
01029
01030
01031
01032
01033
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
01044
01045
01046
01047
01048
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
01058
01059
01060
01061
01062
01063
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
01074 static VALUE
01075 nucomp_true(VALUE self)
01076 {
01077 return Qtrue;
01078 }
01079 #endif
01080
01081
01082
01083
01084
01085
01086
01087 static VALUE
01088 nucomp_false(VALUE self)
01089 {
01090 return Qfalse;
01091 }
01092
01093 #if 0
01094
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
01103 static VALUE
01104 nucomp_inexact_p(VALUE self)
01105 {
01106 return f_boolcast(!nucomp_exact_p(self));
01107 }
01108 #endif
01109
01110
01111
01112
01113
01114
01115
01116
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
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
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
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
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
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241 static VALUE
01242 nucomp_to_s(VALUE self)
01243 {
01244 return f_format(self, f_to_s);
01245 }
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
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
01272 static VALUE
01273 nucomp_dumper(VALUE self)
01274 {
01275 return self;
01276 }
01277
01278
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
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
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
01347
01348
01349
01350
01351
01352
01353
01354
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
01371
01372
01373
01374
01375
01376
01377
01378
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
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
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
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
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
01449
01450
01451
01452
01453
01454
01455
01456 static VALUE
01457 nucomp_to_c(VALUE self)
01458 {
01459 return self;
01460 }
01461
01462
01463
01464
01465
01466
01467
01468 static VALUE
01469 nilclass_to_c(VALUE self)
01470 {
01471 return rb_complex_new1(INT2FIX(0));
01472 }
01473
01474
01475
01476
01477
01478
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;
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;
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;
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;
01684 }
01685 num2 = str2num(bb);
01686 *ret = rb_complex_polar(num, num2);
01687 if (!st)
01688 return 0;
01689 else
01690 return 1;
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;
01702 }
01703 **b = '\0';
01704 num2 = str2num(bb);
01705 }
01706 if (!isimagunit(**s)) {
01707 *ret = rb_complex_new2(num, ZERO);
01708 return 0;
01709 }
01710 (*s)++;
01711 *ret = rb_complex_new2(num, num2);
01712 return 1;
01713 }
01714
01715 {
01716 *ret = rb_complex_new2(num, ZERO);
01717 return 1;
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
01788
01789
01790
01791
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
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
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
01906
01907
01908
01909
01910 static VALUE
01911 numeric_real(VALUE self)
01912 {
01913 return self;
01914 }
01915
01916
01917
01918
01919
01920
01921
01922
01923 static VALUE
01924 numeric_imag(VALUE self)
01925 {
01926 return INT2FIX(0);
01927 }
01928
01929
01930
01931
01932
01933
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
01945
01946
01947
01948
01949
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
01961
01962
01963
01964
01965
01966 static VALUE
01967 numeric_rect(VALUE self)
01968 {
01969 return rb_assoc_new(self, INT2FIX(0));
01970 }
01971
01972
01973
01974
01975
01976
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
01986
01987
01988
01989
01990
01991 static VALUE
01992 numeric_conj(VALUE self)
01993 {
01994 return self;
01995 }
01996
01997
01998
01999
02000
02001
02002
02003
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
02017
02018
02019
02020
02021
02022
02023
02024
02025
02026
02027
02028
02029
02030
02031
02032
02033
02034
02035
02036
02037
02038
02039
02040
02041
02042
02043
02044
02045
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");
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
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);
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
02202
02203 rb_define_const(rb_cComplex, "I",
02204 f_complex_new_bang2(rb_cComplex, ZERO, ONE));
02205 }
02206
02207
02208
02209
02210
02211
02212