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
00460
00461 static VALUE
00462 nucomp_f_complex(int argc, VALUE *argv, VALUE klass)
00463 {
00464 return rb_funcall2(rb_cComplex, id_convert, argc, argv);
00465 }
00466
00467 #define imp1(n) \
00468 inline static VALUE \
00469 m_##n##_bang(VALUE x)\
00470 {\
00471 return rb_math_##n(x);\
00472 }
00473
00474 #define imp2(n) \
00475 inline static VALUE \
00476 m_##n##_bang(VALUE x, VALUE y)\
00477 {\
00478 return rb_math_##n(x, y);\
00479 }
00480
00481 imp2(atan2)
00482 imp1(cos)
00483 imp1(cosh)
00484 imp1(exp)
00485 imp2(hypot)
00486
00487 #define m_hypot(x,y) m_hypot_bang((x),(y))
00488
00489 static VALUE
00490 m_log_bang(VALUE x)
00491 {
00492 return rb_math_log(1, &x);
00493 }
00494
00495 imp1(sin)
00496 imp1(sinh)
00497
00498 static VALUE
00499 m_cos(VALUE x)
00500 {
00501 if (f_real_p(x))
00502 return m_cos_bang(x);
00503 {
00504 get_dat1(x);
00505 return f_complex_new2(rb_cComplex,
00506 f_mul(m_cos_bang(dat->real),
00507 m_cosh_bang(dat->imag)),
00508 f_mul(f_negate(m_sin_bang(dat->real)),
00509 m_sinh_bang(dat->imag)));
00510 }
00511 }
00512
00513 static VALUE
00514 m_sin(VALUE x)
00515 {
00516 if (f_real_p(x))
00517 return m_sin_bang(x);
00518 {
00519 get_dat1(x);
00520 return f_complex_new2(rb_cComplex,
00521 f_mul(m_sin_bang(dat->real),
00522 m_cosh_bang(dat->imag)),
00523 f_mul(m_cos_bang(dat->real),
00524 m_sinh_bang(dat->imag)));
00525 }
00526 }
00527
00528 #if 0
00529 imp1(sqrt)
00530
00531 static VALUE
00532 m_sqrt(VALUE x)
00533 {
00534 if (f_real_p(x)) {
00535 if (f_positive_p(x))
00536 return m_sqrt_bang(x);
00537 return f_complex_new2(rb_cComplex, ZERO, m_sqrt_bang(f_negate(x)));
00538 }
00539 else {
00540 get_dat1(x);
00541
00542 if (f_negative_p(dat->imag))
00543 return f_conj(m_sqrt(f_conj(x)));
00544 else {
00545 VALUE a = f_abs(x);
00546 return f_complex_new2(rb_cComplex,
00547 m_sqrt_bang(f_div(f_add(a, dat->real), TWO)),
00548 m_sqrt_bang(f_div(f_sub(a, dat->real), TWO)));
00549 }
00550 }
00551 }
00552 #endif
00553
00554 inline static VALUE
00555 f_complex_polar(VALUE klass, VALUE x, VALUE y)
00556 {
00557 assert(!k_complex_p(x));
00558 assert(!k_complex_p(y));
00559 return nucomp_s_canonicalize_internal(klass,
00560 f_mul(x, m_cos(y)),
00561 f_mul(x, m_sin(y)));
00562 }
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575 static VALUE
00576 nucomp_s_polar(int argc, VALUE *argv, VALUE klass)
00577 {
00578 VALUE abs, arg;
00579
00580 switch (rb_scan_args(argc, argv, "11", &abs, &arg)) {
00581 case 1:
00582 nucomp_real_check(abs);
00583 arg = ZERO;
00584 break;
00585 default:
00586 nucomp_real_check(abs);
00587 nucomp_real_check(arg);
00588 break;
00589 }
00590 return f_complex_polar(klass, abs, arg);
00591 }
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602 static VALUE
00603 nucomp_real(VALUE self)
00604 {
00605 get_dat1(self);
00606 return dat->real;
00607 }
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619 static VALUE
00620 nucomp_imag(VALUE self)
00621 {
00622 get_dat1(self);
00623 return dat->imag;
00624 }
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634 static VALUE
00635 nucomp_negate(VALUE self)
00636 {
00637 get_dat1(self);
00638 return f_complex_new2(CLASS_OF(self),
00639 f_negate(dat->real), f_negate(dat->imag));
00640 }
00641
00642 inline static VALUE
00643 f_addsub(VALUE self, VALUE other,
00644 VALUE (*func)(VALUE, VALUE), ID id)
00645 {
00646 if (k_complex_p(other)) {
00647 VALUE real, imag;
00648
00649 get_dat2(self, other);
00650
00651 real = (*func)(adat->real, bdat->real);
00652 imag = (*func)(adat->imag, bdat->imag);
00653
00654 return f_complex_new2(CLASS_OF(self), real, imag);
00655 }
00656 if (k_numeric_p(other) && f_real_p(other)) {
00657 get_dat1(self);
00658
00659 return f_complex_new2(CLASS_OF(self),
00660 (*func)(dat->real, other), dat->imag);
00661 }
00662 return rb_num_coerce_bin(self, other, id);
00663 }
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677 static VALUE
00678 nucomp_add(VALUE self, VALUE other)
00679 {
00680 return f_addsub(self, other, f_add, '+');
00681 }
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695 static VALUE
00696 nucomp_sub(VALUE self, VALUE other)
00697 {
00698 return f_addsub(self, other, f_sub, '-');
00699 }
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713 static VALUE
00714 nucomp_mul(VALUE self, VALUE other)
00715 {
00716 if (k_complex_p(other)) {
00717 VALUE real, imag;
00718
00719 get_dat2(self, other);
00720
00721 real = f_sub(f_mul(adat->real, bdat->real),
00722 f_mul(adat->imag, bdat->imag));
00723 imag = f_add(f_mul(adat->real, bdat->imag),
00724 f_mul(adat->imag, bdat->real));
00725
00726 return f_complex_new2(CLASS_OF(self), real, imag);
00727 }
00728 if (k_numeric_p(other) && f_real_p(other)) {
00729 get_dat1(self);
00730
00731 return f_complex_new2(CLASS_OF(self),
00732 f_mul(dat->real, other),
00733 f_mul(dat->imag, other));
00734 }
00735 return rb_num_coerce_bin(self, other, '*');
00736 }
00737
00738 inline static VALUE
00739 f_divide(VALUE self, VALUE other,
00740 VALUE (*func)(VALUE, VALUE), ID id)
00741 {
00742 if (k_complex_p(other)) {
00743 int flo;
00744 get_dat2(self, other);
00745
00746 flo = (k_float_p(adat->real) || k_float_p(adat->imag) ||
00747 k_float_p(bdat->real) || k_float_p(bdat->imag));
00748
00749 if (f_gt_p(f_abs(bdat->real), f_abs(bdat->imag))) {
00750 VALUE r, n;
00751
00752 r = (*func)(bdat->imag, bdat->real);
00753 n = f_mul(bdat->real, f_add(ONE, f_mul(r, r)));
00754 if (flo)
00755 return f_complex_new2(CLASS_OF(self),
00756 (*func)(self, n),
00757 (*func)(f_negate(f_mul(self, r)), n));
00758 return f_complex_new2(CLASS_OF(self),
00759 (*func)(f_add(adat->real,
00760 f_mul(adat->imag, r)), n),
00761 (*func)(f_sub(adat->imag,
00762 f_mul(adat->real, r)), n));
00763 }
00764 else {
00765 VALUE r, n;
00766
00767 r = (*func)(bdat->real, bdat->imag);
00768 n = f_mul(bdat->imag, f_add(ONE, f_mul(r, r)));
00769 if (flo)
00770 return f_complex_new2(CLASS_OF(self),
00771 (*func)(f_mul(self, r), n),
00772 (*func)(f_negate(self), n));
00773 return f_complex_new2(CLASS_OF(self),
00774 (*func)(f_add(f_mul(adat->real, r),
00775 adat->imag), n),
00776 (*func)(f_sub(f_mul(adat->imag, r),
00777 adat->real), n));
00778 }
00779 }
00780 if (k_numeric_p(other) && f_real_p(other)) {
00781 get_dat1(self);
00782
00783 return f_complex_new2(CLASS_OF(self),
00784 (*func)(dat->real, other),
00785 (*func)(dat->imag, other));
00786 }
00787 return rb_num_coerce_bin(self, other, id);
00788 }
00789
00790 #define rb_raise_zerodiv() rb_raise(rb_eZeroDivError, "divided by 0")
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805 static VALUE
00806 nucomp_div(VALUE self, VALUE other)
00807 {
00808 return f_divide(self, other, f_quo, id_quo);
00809 }
00810
00811 #define nucomp_quo nucomp_div
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821 static VALUE
00822 nucomp_fdiv(VALUE self, VALUE other)
00823 {
00824 return f_divide(self, other, f_fdiv, id_fdiv);
00825 }
00826
00827 inline static VALUE
00828 f_reciprocal(VALUE x)
00829 {
00830 return f_quo(ONE, x);
00831 }
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842 static VALUE
00843 nucomp_expt(VALUE self, VALUE other)
00844 {
00845 if (k_numeric_p(other) && k_exact_zero_p(other))
00846 return f_complex_new_bang1(CLASS_OF(self), ONE);
00847
00848 if (k_rational_p(other) && f_one_p(f_denominator(other)))
00849 other = f_numerator(other);
00850
00851 if (k_complex_p(other)) {
00852 get_dat1(other);
00853
00854 if (k_exact_zero_p(dat->imag))
00855 other = dat->real;
00856 }
00857
00858 if (k_complex_p(other)) {
00859 VALUE r, theta, nr, ntheta;
00860
00861 get_dat1(other);
00862
00863 r = f_abs(self);
00864 theta = f_arg(self);
00865
00866 nr = m_exp_bang(f_sub(f_mul(dat->real, m_log_bang(r)),
00867 f_mul(dat->imag, theta)));
00868 ntheta = f_add(f_mul(theta, dat->real),
00869 f_mul(dat->imag, m_log_bang(r)));
00870 return f_complex_polar(CLASS_OF(self), nr, ntheta);
00871 }
00872 if (k_fixnum_p(other)) {
00873 if (f_gt_p(other, ZERO)) {
00874 VALUE x, z;
00875 long n;
00876
00877 x = self;
00878 z = x;
00879 n = FIX2LONG(other) - 1;
00880
00881 while (n) {
00882 long q, r;
00883
00884 while (1) {
00885 get_dat1(x);
00886
00887 q = n / 2;
00888 r = n % 2;
00889
00890 if (r)
00891 break;
00892
00893 x = nucomp_s_new_internal(CLASS_OF(self),
00894 f_sub(f_mul(dat->real, dat->real),
00895 f_mul(dat->imag, dat->imag)),
00896 f_mul(f_mul(TWO, dat->real), dat->imag));
00897 n = q;
00898 }
00899 z = f_mul(z, x);
00900 n--;
00901 }
00902 return z;
00903 }
00904 return f_expt(f_reciprocal(self), f_negate(other));
00905 }
00906 if (k_numeric_p(other) && f_real_p(other)) {
00907 VALUE r, theta;
00908
00909 if (k_bignum_p(other))
00910 rb_warn("in a**b, b may be too big");
00911
00912 r = f_abs(self);
00913 theta = f_arg(self);
00914
00915 return f_complex_polar(CLASS_OF(self), f_expt(r, other),
00916 f_mul(theta, other));
00917 }
00918 return rb_num_coerce_bin(self, other, id_expt);
00919 }
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933 static VALUE
00934 nucomp_eqeq_p(VALUE self, VALUE other)
00935 {
00936 if (k_complex_p(other)) {
00937 get_dat2(self, other);
00938
00939 return f_boolcast(f_eqeq_p(adat->real, bdat->real) &&
00940 f_eqeq_p(adat->imag, bdat->imag));
00941 }
00942 if (k_numeric_p(other) && f_real_p(other)) {
00943 get_dat1(self);
00944
00945 return f_boolcast(f_eqeq_p(dat->real, other) && f_zero_p(dat->imag));
00946 }
00947 return f_eqeq_p(other, self);
00948 }
00949
00950
00951 static VALUE
00952 nucomp_coerce(VALUE self, VALUE other)
00953 {
00954 if (k_numeric_p(other) && f_real_p(other))
00955 return rb_assoc_new(f_complex_new_bang1(CLASS_OF(self), other), self);
00956 if (RB_TYPE_P(other, T_COMPLEX))
00957 return rb_assoc_new(other, self);
00958
00959 rb_raise(rb_eTypeError, "%s can't be coerced into %s",
00960 rb_obj_classname(other), rb_obj_classname(self));
00961 return Qnil;
00962 }
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974 static VALUE
00975 nucomp_abs(VALUE self)
00976 {
00977 get_dat1(self);
00978
00979 if (f_zero_p(dat->real)) {
00980 VALUE a = f_abs(dat->imag);
00981 if (k_float_p(dat->real) && !k_float_p(dat->imag))
00982 a = f_to_f(a);
00983 return a;
00984 }
00985 if (f_zero_p(dat->imag)) {
00986 VALUE a = f_abs(dat->real);
00987 if (!k_float_p(dat->real) && k_float_p(dat->imag))
00988 a = f_to_f(a);
00989 return a;
00990 }
00991 return m_hypot(dat->real, dat->imag);
00992 }
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003 static VALUE
01004 nucomp_abs2(VALUE self)
01005 {
01006 get_dat1(self);
01007 return f_add(f_mul(dat->real, dat->real),
01008 f_mul(dat->imag, dat->imag));
01009 }
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021 static VALUE
01022 nucomp_arg(VALUE self)
01023 {
01024 get_dat1(self);
01025 return m_atan2_bang(dat->imag, dat->real);
01026 }
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037 static VALUE
01038 nucomp_rect(VALUE self)
01039 {
01040 get_dat1(self);
01041 return rb_assoc_new(dat->real, dat->imag);
01042 }
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052 static VALUE
01053 nucomp_polar(VALUE self)
01054 {
01055 return rb_assoc_new(f_abs(self), f_arg(self));
01056 }
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067 static VALUE
01068 nucomp_conj(VALUE self)
01069 {
01070 get_dat1(self);
01071 return f_complex_new2(CLASS_OF(self), dat->real, f_negate(dat->imag));
01072 }
01073
01074 #if 0
01075
01076 static VALUE
01077 nucomp_true(VALUE self)
01078 {
01079 return Qtrue;
01080 }
01081 #endif
01082
01083
01084
01085
01086
01087
01088
01089 static VALUE
01090 nucomp_false(VALUE self)
01091 {
01092 return Qfalse;
01093 }
01094
01095 #if 0
01096
01097 static VALUE
01098 nucomp_exact_p(VALUE self)
01099 {
01100 get_dat1(self);
01101 return f_boolcast(k_exact_p(dat->real) && k_exact_p(dat->imag));
01102 }
01103
01104
01105 static VALUE
01106 nucomp_inexact_p(VALUE self)
01107 {
01108 return f_boolcast(!nucomp_exact_p(self));
01109 }
01110 #endif
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120 static VALUE
01121 nucomp_denominator(VALUE self)
01122 {
01123 get_dat1(self);
01124 return rb_lcm(f_denominator(dat->real), f_denominator(dat->imag));
01125 }
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145 static VALUE
01146 nucomp_numerator(VALUE self)
01147 {
01148 VALUE cd;
01149
01150 get_dat1(self);
01151
01152 cd = f_denominator(self);
01153 return f_complex_new2(CLASS_OF(self),
01154 f_mul(f_numerator(dat->real),
01155 f_div(cd, f_denominator(dat->real))),
01156 f_mul(f_numerator(dat->imag),
01157 f_div(cd, f_denominator(dat->imag))));
01158 }
01159
01160
01161 static VALUE
01162 nucomp_hash(VALUE self)
01163 {
01164 st_index_t v, h[2];
01165 VALUE n;
01166
01167 get_dat1(self);
01168 n = rb_hash(dat->real);
01169 h[0] = NUM2LONG(n);
01170 n = rb_hash(dat->imag);
01171 h[1] = NUM2LONG(n);
01172 v = rb_memhash(h, sizeof(h));
01173 return LONG2FIX(v);
01174 }
01175
01176
01177 static VALUE
01178 nucomp_eql_p(VALUE self, VALUE other)
01179 {
01180 if (k_complex_p(other)) {
01181 get_dat2(self, other);
01182
01183 return f_boolcast((CLASS_OF(adat->real) == CLASS_OF(bdat->real)) &&
01184 (CLASS_OF(adat->imag) == CLASS_OF(bdat->imag)) &&
01185 f_eqeq_p(self, other));
01186
01187 }
01188 return Qfalse;
01189 }
01190
01191 inline static VALUE
01192 f_signbit(VALUE x)
01193 {
01194 #if defined(HAVE_SIGNBIT) && defined(__GNUC__) && defined(__sun) && \
01195 !defined(signbit)
01196 extern int signbit(double);
01197 #endif
01198 if (RB_TYPE_P(x, T_FLOAT)) {
01199 double f = RFLOAT_VALUE(x);
01200 return f_boolcast(!isnan(f) && signbit(f));
01201 }
01202 return f_negative_p(x);
01203 }
01204
01205 inline static VALUE
01206 f_tpositive_p(VALUE x)
01207 {
01208 return f_boolcast(!f_signbit(x));
01209 }
01210
01211 static VALUE
01212 f_format(VALUE self, VALUE (*func)(VALUE))
01213 {
01214 VALUE s, impos;
01215
01216 get_dat1(self);
01217
01218 impos = f_tpositive_p(dat->imag);
01219
01220 s = (*func)(dat->real);
01221 rb_str_cat2(s, !impos ? "-" : "+");
01222
01223 rb_str_concat(s, (*func)(f_abs(dat->imag)));
01224 if (!rb_isdigit(RSTRING_PTR(s)[RSTRING_LEN(s) - 1]))
01225 rb_str_cat2(s, "*");
01226 rb_str_cat2(s, "i");
01227
01228 return s;
01229 }
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243 static VALUE
01244 nucomp_to_s(VALUE self)
01245 {
01246 return f_format(self, f_to_s);
01247 }
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261 static VALUE
01262 nucomp_inspect(VALUE self)
01263 {
01264 VALUE s;
01265
01266 s = rb_usascii_str_new2("(");
01267 rb_str_concat(s, f_format(self, f_inspect));
01268 rb_str_cat2(s, ")");
01269
01270 return s;
01271 }
01272
01273
01274 static VALUE
01275 nucomp_dumper(VALUE self)
01276 {
01277 return self;
01278 }
01279
01280
01281 static VALUE
01282 nucomp_loader(VALUE self, VALUE a)
01283 {
01284 get_dat1(self);
01285
01286 RCOMPLEX_SET_REAL(dat, rb_ivar_get(a, id_i_real));
01287 RCOMPLEX_SET_IMAG(dat, rb_ivar_get(a, id_i_imag));
01288
01289 return self;
01290 }
01291
01292
01293 static VALUE
01294 nucomp_marshal_dump(VALUE self)
01295 {
01296 VALUE a;
01297 get_dat1(self);
01298
01299 a = rb_assoc_new(dat->real, dat->imag);
01300 rb_copy_generic_ivar(a, self);
01301 return a;
01302 }
01303
01304
01305 static VALUE
01306 nucomp_marshal_load(VALUE self, VALUE a)
01307 {
01308 Check_Type(a, T_ARRAY);
01309 if (RARRAY_LEN(a) != 2)
01310 rb_raise(rb_eArgError, "marshaled complex must have an array whose length is 2 but %ld", RARRAY_LEN(a));
01311 rb_ivar_set(self, id_i_real, RARRAY_AREF(a, 0));
01312 rb_ivar_set(self, id_i_imag, RARRAY_AREF(a, 1));
01313 return self;
01314 }
01315
01316
01317
01318 VALUE
01319 rb_complex_raw(VALUE x, VALUE y)
01320 {
01321 return nucomp_s_new_internal(rb_cComplex, x, y);
01322 }
01323
01324 VALUE
01325 rb_complex_new(VALUE x, VALUE y)
01326 {
01327 return nucomp_s_canonicalize_internal(rb_cComplex, x, y);
01328 }
01329
01330 VALUE
01331 rb_complex_polar(VALUE x, VALUE y)
01332 {
01333 return f_complex_polar(rb_cComplex, x, y);
01334 }
01335
01336 static VALUE nucomp_s_convert(int argc, VALUE *argv, VALUE klass);
01337
01338 VALUE
01339 rb_Complex(VALUE x, VALUE y)
01340 {
01341 VALUE a[2];
01342 a[0] = x;
01343 a[1] = y;
01344 return nucomp_s_convert(2, a, rb_cComplex);
01345 }
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357
01358 static VALUE
01359 nucomp_to_i(VALUE self)
01360 {
01361 get_dat1(self);
01362
01363 if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) {
01364 VALUE s = f_to_s(self);
01365 rb_raise(rb_eRangeError, "can't convert %s into Integer",
01366 StringValuePtr(s));
01367 }
01368 return f_to_i(dat->real);
01369 }
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382 static VALUE
01383 nucomp_to_f(VALUE self)
01384 {
01385 get_dat1(self);
01386
01387 if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) {
01388 VALUE s = f_to_s(self);
01389 rb_raise(rb_eRangeError, "can't convert %s into Float",
01390 StringValuePtr(s));
01391 }
01392 return f_to_f(dat->real);
01393 }
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408 static VALUE
01409 nucomp_to_r(VALUE self)
01410 {
01411 get_dat1(self);
01412
01413 if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) {
01414 VALUE s = f_to_s(self);
01415 rb_raise(rb_eRangeError, "can't convert %s into Rational",
01416 StringValuePtr(s));
01417 }
01418 return f_to_r(dat->real);
01419 }
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434 static VALUE
01435 nucomp_rationalize(int argc, VALUE *argv, VALUE self)
01436 {
01437 get_dat1(self);
01438
01439 rb_scan_args(argc, argv, "01", NULL);
01440
01441 if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) {
01442 VALUE s = f_to_s(self);
01443 rb_raise(rb_eRangeError, "can't convert %s into Rational",
01444 StringValuePtr(s));
01445 }
01446 return rb_funcall2(dat->real, rb_intern("rationalize"), argc, argv);
01447 }
01448
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458 static VALUE
01459 nucomp_to_c(VALUE self)
01460 {
01461 return self;
01462 }
01463
01464
01465
01466
01467
01468
01469
01470 static VALUE
01471 nilclass_to_c(VALUE self)
01472 {
01473 return rb_complex_new1(INT2FIX(0));
01474 }
01475
01476
01477
01478
01479
01480
01481
01482 static VALUE
01483 numeric_to_c(VALUE self)
01484 {
01485 return rb_complex_new1(self);
01486 }
01487
01488 #include <ctype.h>
01489
01490 inline static int
01491 issign(int c)
01492 {
01493 return (c == '-' || c == '+');
01494 }
01495
01496 static int
01497 read_sign(const char **s,
01498 char **b)
01499 {
01500 int sign = '?';
01501
01502 if (issign(**s)) {
01503 sign = **b = **s;
01504 (*s)++;
01505 (*b)++;
01506 }
01507 return sign;
01508 }
01509
01510 inline static int
01511 isdecimal(int c)
01512 {
01513 return isdigit((unsigned char)c);
01514 }
01515
01516 static int
01517 read_digits(const char **s, int strict,
01518 char **b)
01519 {
01520 int us = 1;
01521
01522 if (!isdecimal(**s))
01523 return 0;
01524
01525 while (isdecimal(**s) || **s == '_') {
01526 if (**s == '_') {
01527 if (strict) {
01528 if (us)
01529 return 0;
01530 }
01531 us = 1;
01532 }
01533 else {
01534 **b = **s;
01535 (*b)++;
01536 us = 0;
01537 }
01538 (*s)++;
01539 }
01540 if (us)
01541 do {
01542 (*s)--;
01543 } while (**s == '_');
01544 return 1;
01545 }
01546
01547 inline static int
01548 islettere(int c)
01549 {
01550 return (c == 'e' || c == 'E');
01551 }
01552
01553 static int
01554 read_num(const char **s, int strict,
01555 char **b)
01556 {
01557 if (**s != '.') {
01558 if (!read_digits(s, strict, b))
01559 return 0;
01560 }
01561
01562 if (**s == '.') {
01563 **b = **s;
01564 (*s)++;
01565 (*b)++;
01566 if (!read_digits(s, strict, b)) {
01567 (*b)--;
01568 return 0;
01569 }
01570 }
01571
01572 if (islettere(**s)) {
01573 **b = **s;
01574 (*s)++;
01575 (*b)++;
01576 read_sign(s, b);
01577 if (!read_digits(s, strict, b)) {
01578 (*b)--;
01579 return 0;
01580 }
01581 }
01582 return 1;
01583 }
01584
01585 inline static int
01586 read_den(const char **s, int strict,
01587 char **b)
01588 {
01589 if (!read_digits(s, strict, b))
01590 return 0;
01591 return 1;
01592 }
01593
01594 static int
01595 read_rat_nos(const char **s, int strict,
01596 char **b)
01597 {
01598 if (!read_num(s, strict, b))
01599 return 0;
01600 if (**s == '/') {
01601 **b = **s;
01602 (*s)++;
01603 (*b)++;
01604 if (!read_den(s, strict, b)) {
01605 (*b)--;
01606 return 0;
01607 }
01608 }
01609 return 1;
01610 }
01611
01612 static int
01613 read_rat(const char **s, int strict,
01614 char **b)
01615 {
01616 read_sign(s, b);
01617 if (!read_rat_nos(s, strict, b))
01618 return 0;
01619 return 1;
01620 }
01621
01622 inline static int
01623 isimagunit(int c)
01624 {
01625 return (c == 'i' || c == 'I' ||
01626 c == 'j' || c == 'J');
01627 }
01628
01629 VALUE rb_cstr_to_rat(const char *, int);
01630
01631 static VALUE
01632 str2num(char *s)
01633 {
01634 if (strchr(s, '/'))
01635 return rb_cstr_to_rat(s, 0);
01636 if (strpbrk(s, ".eE"))
01637 return DBL2NUM(rb_cstr_to_dbl(s, 0));
01638 return rb_cstr_to_inum(s, 10, 0);
01639 }
01640
01641 static int
01642 read_comp(const char **s, int strict,
01643 VALUE *ret, char **b)
01644 {
01645 char *bb;
01646 int sign;
01647 VALUE num, num2;
01648
01649 bb = *b;
01650
01651 sign = read_sign(s, b);
01652
01653 if (isimagunit(**s)) {
01654 (*s)++;
01655 num = INT2FIX((sign == '-') ? -1 : + 1);
01656 *ret = rb_complex_new2(ZERO, num);
01657 return 1;
01658 }
01659
01660 if (!read_rat_nos(s, strict, b)) {
01661 **b = '\0';
01662 num = str2num(bb);
01663 *ret = rb_complex_new2(num, ZERO);
01664 return 0;
01665 }
01666 **b = '\0';
01667 num = str2num(bb);
01668
01669 if (isimagunit(**s)) {
01670 (*s)++;
01671 *ret = rb_complex_new2(ZERO, num);
01672 return 1;
01673 }
01674
01675 if (**s == '@') {
01676 int st;
01677
01678 (*s)++;
01679 bb = *b;
01680 st = read_rat(s, strict, b);
01681 **b = '\0';
01682 if (strlen(bb) < 1 ||
01683 !isdecimal(*(bb + strlen(bb) - 1))) {
01684 *ret = rb_complex_new2(num, ZERO);
01685 return 0;
01686 }
01687 num2 = str2num(bb);
01688 *ret = rb_complex_polar(num, num2);
01689 if (!st)
01690 return 0;
01691 else
01692 return 1;
01693 }
01694
01695 if (issign(**s)) {
01696 bb = *b;
01697 sign = read_sign(s, b);
01698 if (isimagunit(**s))
01699 num2 = INT2FIX((sign == '-') ? -1 : + 1);
01700 else {
01701 if (!read_rat_nos(s, strict, b)) {
01702 *ret = rb_complex_new2(num, ZERO);
01703 return 0;
01704 }
01705 **b = '\0';
01706 num2 = str2num(bb);
01707 }
01708 if (!isimagunit(**s)) {
01709 *ret = rb_complex_new2(num, ZERO);
01710 return 0;
01711 }
01712 (*s)++;
01713 *ret = rb_complex_new2(num, num2);
01714 return 1;
01715 }
01716
01717 {
01718 *ret = rb_complex_new2(num, ZERO);
01719 return 1;
01720 }
01721 }
01722
01723 inline static void
01724 skip_ws(const char **s)
01725 {
01726 while (isspace((unsigned char)**s))
01727 (*s)++;
01728 }
01729
01730 static int
01731 parse_comp(const char *s, int strict,
01732 VALUE *num)
01733 {
01734 char *buf, *b;
01735 VALUE tmp;
01736 int ret = 1;
01737
01738 buf = ALLOCV_N(char, tmp, strlen(s) + 1);
01739 b = buf;
01740
01741 skip_ws(&s);
01742 if (!read_comp(&s, strict, num, &b)) {
01743 ret = 0;
01744 }
01745 else {
01746 skip_ws(&s);
01747
01748 if (strict)
01749 if (*s != '\0')
01750 ret = 0;
01751 }
01752 ALLOCV_END(tmp);
01753
01754 return ret;
01755 }
01756
01757 static VALUE
01758 string_to_c_strict(VALUE self)
01759 {
01760 char *s;
01761 VALUE num;
01762
01763 rb_must_asciicompat(self);
01764
01765 s = RSTRING_PTR(self);
01766
01767 if (!s || memchr(s, '\0', RSTRING_LEN(self)))
01768 rb_raise(rb_eArgError, "string contains null byte");
01769
01770 if (s && s[RSTRING_LEN(self)]) {
01771 rb_str_modify(self);
01772 s = RSTRING_PTR(self);
01773 s[RSTRING_LEN(self)] = '\0';
01774 }
01775
01776 if (!s)
01777 s = (char *)"";
01778
01779 if (!parse_comp(s, 1, &num)) {
01780 VALUE ins = f_inspect(self);
01781 rb_raise(rb_eArgError, "invalid value for convert(): %s",
01782 StringValuePtr(ins));
01783 }
01784
01785 return num;
01786 }
01787
01788
01789
01790
01791
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811 static VALUE
01812 string_to_c(VALUE self)
01813 {
01814 char *s;
01815 VALUE num;
01816
01817 rb_must_asciicompat(self);
01818
01819 s = RSTRING_PTR(self);
01820
01821 if (s && s[RSTRING_LEN(self)]) {
01822 rb_str_modify(self);
01823 s = RSTRING_PTR(self);
01824 s[RSTRING_LEN(self)] = '\0';
01825 }
01826
01827 if (!s)
01828 s = (char *)"";
01829
01830 (void)parse_comp(s, 0, &num);
01831
01832 return num;
01833 }
01834
01835 static VALUE
01836 nucomp_s_convert(int argc, VALUE *argv, VALUE klass)
01837 {
01838 VALUE a1, a2, backref;
01839
01840 rb_scan_args(argc, argv, "11", &a1, &a2);
01841
01842 if (NIL_P(a1) || (argc == 2 && NIL_P(a2)))
01843 rb_raise(rb_eTypeError, "can't convert nil into Complex");
01844
01845 backref = rb_backref_get();
01846 rb_match_busy(backref);
01847
01848 if (RB_TYPE_P(a1, T_STRING)) {
01849 a1 = string_to_c_strict(a1);
01850 }
01851
01852 if (RB_TYPE_P(a2, T_STRING)) {
01853 a2 = string_to_c_strict(a2);
01854 }
01855
01856 rb_backref_set(backref);
01857
01858 if (RB_TYPE_P(a1, T_COMPLEX)) {
01859 {
01860 get_dat1(a1);
01861
01862 if (k_exact_zero_p(dat->imag))
01863 a1 = dat->real;
01864 }
01865 }
01866
01867 if (RB_TYPE_P(a2, T_COMPLEX)) {
01868 {
01869 get_dat1(a2);
01870
01871 if (k_exact_zero_p(dat->imag))
01872 a2 = dat->real;
01873 }
01874 }
01875
01876 if (RB_TYPE_P(a1, T_COMPLEX)) {
01877 if (argc == 1 || (k_exact_zero_p(a2)))
01878 return a1;
01879 }
01880
01881 if (argc == 1) {
01882 if (k_numeric_p(a1) && !f_real_p(a1))
01883 return a1;
01884
01885 if (!k_numeric_p(a1))
01886 return rb_convert_type(a1, T_COMPLEX, "Complex", "to_c");
01887 }
01888 else {
01889 if ((k_numeric_p(a1) && k_numeric_p(a2)) &&
01890 (!f_real_p(a1) || !f_real_p(a2)))
01891 return f_add(a1,
01892 f_mul(a2,
01893 f_complex_new_bang2(rb_cComplex, ZERO, ONE)));
01894 }
01895
01896 {
01897 VALUE argv2[2];
01898 argv2[0] = a1;
01899 argv2[1] = a2;
01900 return nucomp_s_new(argc, argv2, klass);
01901 }
01902 }
01903
01904
01905
01906
01907
01908
01909
01910
01911
01912 static VALUE
01913 numeric_real(VALUE self)
01914 {
01915 return self;
01916 }
01917
01918
01919
01920
01921
01922
01923
01924
01925 static VALUE
01926 numeric_imag(VALUE self)
01927 {
01928 return INT2FIX(0);
01929 }
01930
01931
01932
01933
01934
01935
01936
01937 static VALUE
01938 numeric_abs2(VALUE self)
01939 {
01940 return f_mul(self, self);
01941 }
01942
01943 #define id_PI rb_intern("PI")
01944
01945
01946
01947
01948
01949
01950
01951
01952
01953 static VALUE
01954 numeric_arg(VALUE self)
01955 {
01956 if (f_positive_p(self))
01957 return INT2FIX(0);
01958 return rb_const_get(rb_mMath, id_PI);
01959 }
01960
01961
01962
01963
01964
01965
01966
01967
01968 static VALUE
01969 numeric_rect(VALUE self)
01970 {
01971 return rb_assoc_new(self, INT2FIX(0));
01972 }
01973
01974
01975
01976
01977
01978
01979
01980 static VALUE
01981 numeric_polar(VALUE self)
01982 {
01983 return rb_assoc_new(f_abs(self), f_arg(self));
01984 }
01985
01986
01987
01988
01989
01990
01991
01992
01993 static VALUE
01994 numeric_conj(VALUE self)
01995 {
01996 return self;
01997 }
01998
01999
02000
02001
02002
02003
02004
02005
02006
02007 static VALUE
02008 float_arg(VALUE self)
02009 {
02010 if (isnan(RFLOAT_VALUE(self)))
02011 return self;
02012 if (f_tpositive_p(self))
02013 return INT2FIX(0);
02014 return rb_const_get(rb_mMath, id_PI);
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
02048
02049 void
02050 Init_Complex(void)
02051 {
02052 VALUE compat;
02053 #undef rb_intern
02054 #define rb_intern(str) rb_intern_const(str)
02055
02056 assert(fprintf(stderr, "assert() is now active\n"));
02057
02058 id_abs = rb_intern("abs");
02059 id_arg = rb_intern("arg");
02060 id_convert = rb_intern("convert");
02061 id_denominator = rb_intern("denominator");
02062 id_eqeq_p = rb_intern("==");
02063 id_expt = rb_intern("**");
02064 id_fdiv = rb_intern("fdiv");
02065 id_inspect = rb_intern("inspect");
02066 id_negate = rb_intern("-@");
02067 id_numerator = rb_intern("numerator");
02068 id_quo = rb_intern("quo");
02069 id_real_p = rb_intern("real?");
02070 id_to_f = rb_intern("to_f");
02071 id_to_i = rb_intern("to_i");
02072 id_to_r = rb_intern("to_r");
02073 id_to_s = rb_intern("to_s");
02074 id_i_real = rb_intern("@real");
02075 id_i_imag = rb_intern("@image");
02076
02077 rb_cComplex = rb_define_class("Complex", rb_cNumeric);
02078
02079 rb_define_alloc_func(rb_cComplex, nucomp_s_alloc);
02080 rb_undef_method(CLASS_OF(rb_cComplex), "allocate");
02081
02082 #if 0
02083 rb_define_private_method(CLASS_OF(rb_cComplex), "new!", nucomp_s_new_bang, -1);
02084 rb_define_private_method(CLASS_OF(rb_cComplex), "new", nucomp_s_new, -1);
02085 #else
02086 rb_undef_method(CLASS_OF(rb_cComplex), "new");
02087 #endif
02088
02089 rb_define_singleton_method(rb_cComplex, "rectangular", nucomp_s_new, -1);
02090 rb_define_singleton_method(rb_cComplex, "rect", nucomp_s_new, -1);
02091 rb_define_singleton_method(rb_cComplex, "polar", nucomp_s_polar, -1);
02092
02093 rb_define_global_function("Complex", nucomp_f_complex, -1);
02094
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, ">");
02100 rb_undef_method(rb_cComplex, ">=");
02101 rb_undef_method(rb_cComplex, "between?");
02102 rb_undef_method(rb_cComplex, "div");
02103 rb_undef_method(rb_cComplex, "divmod");
02104 rb_undef_method(rb_cComplex, "floor");
02105 rb_undef_method(rb_cComplex, "ceil");
02106 rb_undef_method(rb_cComplex, "modulo");
02107 rb_undef_method(rb_cComplex, "remainder");
02108 rb_undef_method(rb_cComplex, "round");
02109 rb_undef_method(rb_cComplex, "step");
02110 rb_undef_method(rb_cComplex, "truncate");
02111 rb_undef_method(rb_cComplex, "i");
02112
02113 #if 0
02114 rb_undef_method(rb_cComplex, "//");
02115 #endif
02116
02117 rb_define_method(rb_cComplex, "real", nucomp_real, 0);
02118 rb_define_method(rb_cComplex, "imaginary", nucomp_imag, 0);
02119 rb_define_method(rb_cComplex, "imag", nucomp_imag, 0);
02120
02121 rb_define_method(rb_cComplex, "-@", nucomp_negate, 0);
02122 rb_define_method(rb_cComplex, "+", nucomp_add, 1);
02123 rb_define_method(rb_cComplex, "-", nucomp_sub, 1);
02124 rb_define_method(rb_cComplex, "*", nucomp_mul, 1);
02125 rb_define_method(rb_cComplex, "/", nucomp_div, 1);
02126 rb_define_method(rb_cComplex, "quo", nucomp_quo, 1);
02127 rb_define_method(rb_cComplex, "fdiv", nucomp_fdiv, 1);
02128 rb_define_method(rb_cComplex, "**", nucomp_expt, 1);
02129
02130 rb_define_method(rb_cComplex, "==", nucomp_eqeq_p, 1);
02131 rb_define_method(rb_cComplex, "coerce", nucomp_coerce, 1);
02132
02133 rb_define_method(rb_cComplex, "abs", nucomp_abs, 0);
02134 rb_define_method(rb_cComplex, "magnitude", nucomp_abs, 0);
02135 rb_define_method(rb_cComplex, "abs2", nucomp_abs2, 0);
02136 rb_define_method(rb_cComplex, "arg", nucomp_arg, 0);
02137 rb_define_method(rb_cComplex, "angle", nucomp_arg, 0);
02138 rb_define_method(rb_cComplex, "phase", nucomp_arg, 0);
02139 rb_define_method(rb_cComplex, "rectangular", nucomp_rect, 0);
02140 rb_define_method(rb_cComplex, "rect", nucomp_rect, 0);
02141 rb_define_method(rb_cComplex, "polar", nucomp_polar, 0);
02142 rb_define_method(rb_cComplex, "conjugate", nucomp_conj, 0);
02143 rb_define_method(rb_cComplex, "conj", nucomp_conj, 0);
02144 #if 0
02145 rb_define_method(rb_cComplex, "~", nucomp_conj, 0);
02146 #endif
02147
02148 rb_define_method(rb_cComplex, "real?", nucomp_false, 0);
02149 #if 0
02150 rb_define_method(rb_cComplex, "complex?", nucomp_true, 0);
02151 rb_define_method(rb_cComplex, "exact?", nucomp_exact_p, 0);
02152 rb_define_method(rb_cComplex, "inexact?", nucomp_inexact_p, 0);
02153 #endif
02154
02155 rb_define_method(rb_cComplex, "numerator", nucomp_numerator, 0);
02156 rb_define_method(rb_cComplex, "denominator", nucomp_denominator, 0);
02157
02158 rb_define_method(rb_cComplex, "hash", nucomp_hash, 0);
02159 rb_define_method(rb_cComplex, "eql?", nucomp_eql_p, 1);
02160
02161 rb_define_method(rb_cComplex, "to_s", nucomp_to_s, 0);
02162 rb_define_method(rb_cComplex, "inspect", nucomp_inspect, 0);
02163
02164 rb_define_private_method(rb_cComplex, "marshal_dump", nucomp_marshal_dump, 0);
02165 compat = rb_define_class_under(rb_cComplex, "compatible", rb_cObject);
02166 rb_define_private_method(compat, "marshal_load", nucomp_marshal_load, 1);
02167 rb_marshal_define_compat(rb_cComplex, compat, nucomp_dumper, nucomp_loader);
02168
02169
02170
02171 rb_define_method(rb_cComplex, "to_i", nucomp_to_i, 0);
02172 rb_define_method(rb_cComplex, "to_f", nucomp_to_f, 0);
02173 rb_define_method(rb_cComplex, "to_r", nucomp_to_r, 0);
02174 rb_define_method(rb_cComplex, "rationalize", nucomp_rationalize, -1);
02175 rb_define_method(rb_cComplex, "to_c", nucomp_to_c, 0);
02176 rb_define_method(rb_cNilClass, "to_c", nilclass_to_c, 0);
02177 rb_define_method(rb_cNumeric, "to_c", numeric_to_c, 0);
02178
02179 rb_define_method(rb_cString, "to_c", string_to_c, 0);
02180
02181 rb_define_private_method(CLASS_OF(rb_cComplex), "convert", nucomp_s_convert, -1);
02182
02183
02184
02185 rb_define_method(rb_cNumeric, "real", numeric_real, 0);
02186 rb_define_method(rb_cNumeric, "imaginary", numeric_imag, 0);
02187 rb_define_method(rb_cNumeric, "imag", numeric_imag, 0);
02188 rb_define_method(rb_cNumeric, "abs2", numeric_abs2, 0);
02189 rb_define_method(rb_cNumeric, "arg", numeric_arg, 0);
02190 rb_define_method(rb_cNumeric, "angle", numeric_arg, 0);
02191 rb_define_method(rb_cNumeric, "phase", numeric_arg, 0);
02192 rb_define_method(rb_cNumeric, "rectangular", numeric_rect, 0);
02193 rb_define_method(rb_cNumeric, "rect", numeric_rect, 0);
02194 rb_define_method(rb_cNumeric, "polar", numeric_polar, 0);
02195 rb_define_method(rb_cNumeric, "conjugate", numeric_conj, 0);
02196 rb_define_method(rb_cNumeric, "conj", numeric_conj, 0);
02197
02198 rb_define_method(rb_cFloat, "arg", float_arg, 0);
02199 rb_define_method(rb_cFloat, "angle", float_arg, 0);
02200 rb_define_method(rb_cFloat, "phase", float_arg, 0);
02201
02202
02203
02204
02205 rb_define_const(rb_cComplex, "I",
02206 f_complex_new_bang2(rb_cComplex, ZERO, ONE));
02207 }
02208
02209
02210
02211
02212
02213
02214