00001
00002
00003
00004
00005
00006
00007
00008 #include "ruby.h"
00009 #include <math.h>
00010
00011 #define NDEBUG
00012 #include <assert.h>
00013
00014 #define ZERO INT2FIX(0)
00015 #define ONE INT2FIX(1)
00016 #define TWO INT2FIX(2)
00017
00018 VALUE rb_cComplex;
00019
00020 static ID id_abs, id_abs2, id_arg, id_cmp, id_conj, id_convert,
00021 id_denominator, id_divmod, id_eqeq_p, id_expt, id_fdiv, id_floor,
00022 id_idiv, id_imag, id_inspect, id_negate, id_numerator, id_quo,
00023 id_real, id_real_p, id_to_f, id_to_i, id_to_r, id_to_s;
00024
00025 #define f_boolcast(x) ((x) ? Qtrue : Qfalse)
00026
00027 #define binop(n,op) \
00028 inline static VALUE \
00029 f_##n(VALUE x, VALUE y)\
00030 {\
00031 return rb_funcall(x, op, 1, y);\
00032 }
00033
00034 #define fun1(n) \
00035 inline static VALUE \
00036 f_##n(VALUE x)\
00037 {\
00038 return rb_funcall(x, id_##n, 0);\
00039 }
00040
00041 #define fun2(n) \
00042 inline static VALUE \
00043 f_##n(VALUE x, VALUE y)\
00044 {\
00045 return rb_funcall(x, id_##n, 1, y);\
00046 }
00047
00048 #define math1(n) \
00049 inline static VALUE \
00050 m_##n(VALUE x)\
00051 {\
00052 return rb_funcall(rb_mMath, id_##n, 1, x);\
00053 }
00054
00055 #define math2(n) \
00056 inline static VALUE \
00057 m_##n(VALUE x, VALUE y)\
00058 {\
00059 return rb_funcall(rb_mMath, id_##n, 2, x, y);\
00060 }
00061
00062 #define PRESERVE_SIGNEDZERO
00063
00064 inline static VALUE
00065 f_add(VALUE x, VALUE y)
00066 {
00067 #ifndef PRESERVE_SIGNEDZERO
00068 if (FIXNUM_P(y) && FIX2LONG(y) == 0)
00069 return x;
00070 else if (FIXNUM_P(x) && FIX2LONG(x) == 0)
00071 return y;
00072 #endif
00073 return rb_funcall(x, '+', 1, y);
00074 }
00075
00076 inline static VALUE
00077 f_cmp(VALUE x, VALUE y)
00078 {
00079 if (FIXNUM_P(x) && FIXNUM_P(y)) {
00080 long c = FIX2LONG(x) - FIX2LONG(y);
00081 if (c > 0)
00082 c = 1;
00083 else if (c < 0)
00084 c = -1;
00085 return INT2FIX(c);
00086 }
00087 return rb_funcall(x, id_cmp, 1, y);
00088 }
00089
00090 inline static VALUE
00091 f_div(VALUE x, VALUE y)
00092 {
00093 if (FIXNUM_P(y) && FIX2LONG(y) == 1)
00094 return x;
00095 return rb_funcall(x, '/', 1, y);
00096 }
00097
00098 inline static VALUE
00099 f_gt_p(VALUE x, VALUE y)
00100 {
00101 if (FIXNUM_P(x) && FIXNUM_P(y))
00102 return f_boolcast(FIX2LONG(x) > FIX2LONG(y));
00103 return rb_funcall(x, '>', 1, y);
00104 }
00105
00106 inline static VALUE
00107 f_lt_p(VALUE x, VALUE y)
00108 {
00109 if (FIXNUM_P(x) && FIXNUM_P(y))
00110 return f_boolcast(FIX2LONG(x) < FIX2LONG(y));
00111 return rb_funcall(x, '<', 1, y);
00112 }
00113
00114 binop(mod, '%')
00115
00116 inline static VALUE
00117 f_mul(VALUE x, VALUE y)
00118 {
00119 #ifndef PRESERVE_SIGNEDZERO
00120 if (FIXNUM_P(y)) {
00121 long iy = FIX2LONG(y);
00122 if (iy == 0) {
00123 if (FIXNUM_P(x) || TYPE(x) == T_BIGNUM)
00124 return ZERO;
00125 }
00126 else if (iy == 1)
00127 return x;
00128 }
00129 else if (FIXNUM_P(x)) {
00130 long ix = FIX2LONG(x);
00131 if (ix == 0) {
00132 if (FIXNUM_P(y) || TYPE(y) == T_BIGNUM)
00133 return ZERO;
00134 }
00135 else if (ix == 1)
00136 return y;
00137 }
00138 #endif
00139 return rb_funcall(x, '*', 1, y);
00140 }
00141
00142 inline static VALUE
00143 f_sub(VALUE x, VALUE y)
00144 {
00145 #ifndef PRESERVE_SIGNEDZERO
00146 if (FIXNUM_P(y) && FIX2LONG(y) == 0)
00147 return x;
00148 #endif
00149 return rb_funcall(x, '-', 1, y);
00150 }
00151
00152 fun1(abs)
00153 fun1(abs2)
00154 fun1(arg)
00155 fun1(conj)
00156 fun1(denominator)
00157 fun1(floor)
00158 fun1(imag)
00159 fun1(inspect)
00160 fun1(negate)
00161 fun1(numerator)
00162 fun1(real)
00163 fun1(real_p)
00164
00165 fun1(to_f)
00166 fun1(to_i)
00167 fun1(to_r)
00168 fun1(to_s)
00169
00170 fun2(divmod)
00171
00172 inline static VALUE
00173 f_eqeq_p(VALUE x, VALUE y)
00174 {
00175 if (FIXNUM_P(x) && FIXNUM_P(y))
00176 return f_boolcast(FIX2LONG(x) == FIX2LONG(y));
00177 return rb_funcall(x, id_eqeq_p, 1, y);
00178 }
00179
00180 fun2(expt)
00181 fun2(fdiv)
00182 fun2(idiv)
00183 fun2(quo)
00184
00185 inline static VALUE
00186 f_negative_p(VALUE x)
00187 {
00188 if (FIXNUM_P(x))
00189 return f_boolcast(FIX2LONG(x) < 0);
00190 return rb_funcall(x, '<', 1, ZERO);
00191 }
00192
00193 #define f_positive_p(x) (!f_negative_p(x))
00194
00195 inline static VALUE
00196 f_zero_p(VALUE x)
00197 {
00198 switch (TYPE(x)) {
00199 case T_FIXNUM:
00200 return f_boolcast(FIX2LONG(x) == 0);
00201 case T_BIGNUM:
00202 return Qfalse;
00203 case T_RATIONAL:
00204 {
00205 VALUE num = RRATIONAL(x)->num;
00206
00207 return f_boolcast(FIXNUM_P(num) && FIX2LONG(num) == 0);
00208 }
00209 }
00210 return rb_funcall(x, id_eqeq_p, 1, ZERO);
00211 }
00212
00213 #define f_nonzero_p(x) (!f_zero_p(x))
00214
00215 inline static VALUE
00216 f_one_p(VALUE x)
00217 {
00218 switch (TYPE(x)) {
00219 case T_FIXNUM:
00220 return f_boolcast(FIX2LONG(x) == 1);
00221 case T_BIGNUM:
00222 return Qfalse;
00223 case T_RATIONAL:
00224 {
00225 VALUE num = RRATIONAL(x)->num;
00226 VALUE den = RRATIONAL(x)->den;
00227
00228 return f_boolcast(FIXNUM_P(num) && FIX2LONG(num) == 1 &&
00229 FIXNUM_P(den) && FIX2LONG(den) == 1);
00230 }
00231 }
00232 return rb_funcall(x, id_eqeq_p, 1, ONE);
00233 }
00234
00235 inline static VALUE
00236 f_kind_of_p(VALUE x, VALUE c)
00237 {
00238 return rb_obj_is_kind_of(x, c);
00239 }
00240
00241 inline static VALUE
00242 k_numeric_p(VALUE x)
00243 {
00244 return f_kind_of_p(x, rb_cNumeric);
00245 }
00246
00247 inline static VALUE
00248 k_integer_p(VALUE x)
00249 {
00250 return f_kind_of_p(x, rb_cInteger);
00251 }
00252
00253 inline static VALUE
00254 k_fixnum_p(VALUE x)
00255 {
00256 return f_kind_of_p(x, rb_cFixnum);
00257 }
00258
00259 inline static VALUE
00260 k_bignum_p(VALUE x)
00261 {
00262 return f_kind_of_p(x, rb_cBignum);
00263 }
00264
00265 inline static VALUE
00266 k_float_p(VALUE x)
00267 {
00268 return f_kind_of_p(x, rb_cFloat);
00269 }
00270
00271 inline static VALUE
00272 k_rational_p(VALUE x)
00273 {
00274 return f_kind_of_p(x, rb_cRational);
00275 }
00276
00277 inline static VALUE
00278 k_complex_p(VALUE x)
00279 {
00280 return f_kind_of_p(x, rb_cComplex);
00281 }
00282
00283 #define k_exact_p(x) (!k_float_p(x))
00284 #define k_inexact_p(x) k_float_p(x)
00285
00286 #define k_exact_zero_p(x) (k_exact_p(x) && f_zero_p(x))
00287 #define k_exact_one_p(x) (k_exact_p(x) && f_one_p(x))
00288
00289 #define get_dat1(x) \
00290 struct RComplex *dat;\
00291 dat = ((struct RComplex *)(x))
00292
00293 #define get_dat2(x,y) \
00294 struct RComplex *adat, *bdat;\
00295 adat = ((struct RComplex *)(x));\
00296 bdat = ((struct RComplex *)(y))
00297
00298 inline static VALUE
00299 nucomp_s_new_internal(VALUE klass, VALUE real, VALUE imag)
00300 {
00301 NEWOBJ(obj, struct RComplex);
00302 OBJSETUP(obj, klass, T_COMPLEX);
00303
00304 obj->real = real;
00305 obj->imag = imag;
00306
00307 return (VALUE)obj;
00308 }
00309
00310 static VALUE
00311 nucomp_s_alloc(VALUE klass)
00312 {
00313 return nucomp_s_new_internal(klass, ZERO, ZERO);
00314 }
00315
00316 #if 0
00317 static VALUE
00318 nucomp_s_new_bang(int argc, VALUE *argv, VALUE klass)
00319 {
00320 VALUE real, imag;
00321
00322 switch (rb_scan_args(argc, argv, "11", &real, &imag)) {
00323 case 1:
00324 if (!k_numeric_p(real))
00325 real = f_to_i(real);
00326 imag = ZERO;
00327 break;
00328 default:
00329 if (!k_numeric_p(real))
00330 real = f_to_i(real);
00331 if (!k_numeric_p(imag))
00332 imag = f_to_i(imag);
00333 break;
00334 }
00335
00336 return nucomp_s_new_internal(klass, real, imag);
00337 }
00338 #endif
00339
00340 inline static VALUE
00341 f_complex_new_bang1(VALUE klass, VALUE x)
00342 {
00343 assert(!k_complex_p(x));
00344 return nucomp_s_new_internal(klass, x, ZERO);
00345 }
00346
00347 inline static VALUE
00348 f_complex_new_bang2(VALUE klass, VALUE x, VALUE y)
00349 {
00350 assert(!k_complex_p(x));
00351 assert(!k_complex_p(y));
00352 return nucomp_s_new_internal(klass, x, y);
00353 }
00354
00355 #ifdef CANONICALIZATION_FOR_MATHN
00356 #define CANON
00357 #endif
00358
00359 #ifdef CANON
00360 static int canonicalization = 0;
00361
00362 void
00363 nucomp_canonicalization(int f)
00364 {
00365 canonicalization = f;
00366 }
00367 #endif
00368
00369 inline static void
00370 nucomp_real_check(VALUE num)
00371 {
00372 switch (TYPE(num)) {
00373 case T_FIXNUM:
00374 case T_BIGNUM:
00375 case T_FLOAT:
00376 case T_RATIONAL:
00377 break;
00378 default:
00379 if (!k_numeric_p(num) || !f_real_p(num))
00380 rb_raise(rb_eTypeError, "not a real");
00381 }
00382 }
00383
00384 inline static VALUE
00385 nucomp_s_canonicalize_internal(VALUE klass, VALUE real, VALUE imag)
00386 {
00387 #ifdef CANON
00388 #define CL_CANON
00389 #ifdef CL_CANON
00390 if (k_exact_zero_p(imag) && canonicalization)
00391 return real;
00392 #else
00393 if (f_zero_p(imag) && canonicalization)
00394 return real;
00395 #endif
00396 #endif
00397 if (f_real_p(real) && f_real_p(imag))
00398 return nucomp_s_new_internal(klass, real, imag);
00399 else if (f_real_p(real)) {
00400 get_dat1(imag);
00401
00402 return nucomp_s_new_internal(klass,
00403 f_sub(real, dat->imag),
00404 f_add(ZERO, dat->real));
00405 }
00406 else if (f_real_p(imag)) {
00407 get_dat1(real);
00408
00409 return nucomp_s_new_internal(klass,
00410 dat->real,
00411 f_add(dat->imag, imag));
00412 }
00413 else {
00414 get_dat2(real, imag);
00415
00416 return nucomp_s_new_internal(klass,
00417 f_sub(adat->real, bdat->imag),
00418 f_add(adat->imag, bdat->real));
00419 }
00420 }
00421
00422
00423
00424
00425
00426
00427
00428
00429 static VALUE
00430 nucomp_s_new(int argc, VALUE *argv, VALUE klass)
00431 {
00432 VALUE real, imag;
00433
00434 switch (rb_scan_args(argc, argv, "11", &real, &imag)) {
00435 case 1:
00436 nucomp_real_check(real);
00437 imag = ZERO;
00438 break;
00439 default:
00440 nucomp_real_check(real);
00441 nucomp_real_check(imag);
00442 break;
00443 }
00444
00445 return nucomp_s_canonicalize_internal(klass, real, imag);
00446 }
00447
00448 inline static VALUE
00449 f_complex_new1(VALUE klass, VALUE x)
00450 {
00451 assert(!k_complex_p(x));
00452 return nucomp_s_canonicalize_internal(klass, x, ZERO);
00453 }
00454
00455 inline static VALUE
00456 f_complex_new2(VALUE klass, VALUE x, VALUE y)
00457 {
00458 assert(!k_complex_p(x));
00459 return nucomp_s_canonicalize_internal(klass, x, y);
00460 }
00461
00462
00463
00464
00465
00466
00467
00468 static VALUE
00469 nucomp_f_complex(int argc, VALUE *argv, VALUE klass)
00470 {
00471 return rb_funcall2(rb_cComplex, id_convert, argc, argv);
00472 }
00473
00474 #define imp1(n) \
00475 extern VALUE rb_math_##n(VALUE x);\
00476 inline static VALUE \
00477 m_##n##_bang(VALUE x)\
00478 {\
00479 return rb_math_##n(x);\
00480 }
00481
00482 #define imp2(n) \
00483 extern VALUE rb_math_##n(VALUE x, VALUE y);\
00484 inline static VALUE \
00485 m_##n##_bang(VALUE x, VALUE y)\
00486 {\
00487 return rb_math_##n(x, y);\
00488 }
00489
00490 imp2(atan2)
00491 imp1(cos)
00492 imp1(cosh)
00493 imp1(exp)
00494 imp2(hypot)
00495
00496 #define m_hypot(x,y) m_hypot_bang(x,y)
00497
00498 extern VALUE rb_math_log(int argc, VALUE *argv);
00499
00500 static VALUE
00501 m_log_bang(VALUE x)
00502 {
00503 return rb_math_log(1, &x);
00504 }
00505
00506 imp1(sin)
00507 imp1(sinh)
00508 imp1(sqrt)
00509
00510 static VALUE
00511 m_cos(VALUE x)
00512 {
00513 if (f_real_p(x))
00514 return m_cos_bang(x);
00515 {
00516 get_dat1(x);
00517 return f_complex_new2(rb_cComplex,
00518 f_mul(m_cos_bang(dat->real),
00519 m_cosh_bang(dat->imag)),
00520 f_mul(f_negate(m_sin_bang(dat->real)),
00521 m_sinh_bang(dat->imag)));
00522 }
00523 }
00524
00525 static VALUE
00526 m_sin(VALUE x)
00527 {
00528 if (f_real_p(x))
00529 return m_sin_bang(x);
00530 {
00531 get_dat1(x);
00532 return f_complex_new2(rb_cComplex,
00533 f_mul(m_sin_bang(dat->real),
00534 m_cosh_bang(dat->imag)),
00535 f_mul(m_cos_bang(dat->real),
00536 m_sinh_bang(dat->imag)));
00537 }
00538 }
00539
00540 #if 0
00541 static VALUE
00542 m_sqrt(VALUE x)
00543 {
00544 if (f_real_p(x)) {
00545 if (f_positive_p(x))
00546 return m_sqrt_bang(x);
00547 return f_complex_new2(rb_cComplex, ZERO, m_sqrt_bang(f_negate(x)));
00548 }
00549 else {
00550 get_dat1(x);
00551
00552 if (f_negative_p(dat->imag))
00553 return f_conj(m_sqrt(f_conj(x)));
00554 else {
00555 VALUE a = f_abs(x);
00556 return f_complex_new2(rb_cComplex,
00557 m_sqrt_bang(f_div(f_add(a, dat->real), TWO)),
00558 m_sqrt_bang(f_div(f_sub(a, dat->real), TWO)));
00559 }
00560 }
00561 }
00562 #endif
00563
00564 inline static VALUE
00565 f_complex_polar(VALUE klass, VALUE x, VALUE y)
00566 {
00567 assert(!k_complex_p(x));
00568 assert(!k_complex_p(y));
00569 return nucomp_s_canonicalize_internal(klass,
00570 f_mul(x, m_cos(y)),
00571 f_mul(x, m_sin(y)));
00572 }
00573
00574
00575
00576
00577
00578
00579
00580 static VALUE
00581 nucomp_s_polar(int argc, VALUE *argv, VALUE klass)
00582 {
00583 VALUE abs, arg;
00584
00585 switch (rb_scan_args(argc, argv, "11", &abs, &arg)) {
00586 case 1:
00587 nucomp_real_check(abs);
00588 arg = ZERO;
00589 break;
00590 default:
00591 nucomp_real_check(abs);
00592 nucomp_real_check(arg);
00593 break;
00594 }
00595 return f_complex_polar(klass, abs, arg);
00596 }
00597
00598
00599
00600
00601
00602
00603
00604 static VALUE
00605 nucomp_real(VALUE self)
00606 {
00607 get_dat1(self);
00608 return dat->real;
00609 }
00610
00611
00612
00613
00614
00615
00616
00617
00618 static VALUE
00619 nucomp_imag(VALUE self)
00620 {
00621 get_dat1(self);
00622 return dat->imag;
00623 }
00624
00625
00626
00627
00628
00629
00630
00631 static VALUE
00632 nucomp_negate(VALUE self)
00633 {
00634 get_dat1(self);
00635 return f_complex_new2(CLASS_OF(self),
00636 f_negate(dat->real), f_negate(dat->imag));
00637 }
00638
00639 inline static VALUE
00640 f_addsub(VALUE self, VALUE other,
00641 VALUE (*func)(VALUE, VALUE), ID id)
00642 {
00643 if (k_complex_p(other)) {
00644 VALUE real, imag;
00645
00646 get_dat2(self, other);
00647
00648 real = (*func)(adat->real, bdat->real);
00649 imag = (*func)(adat->imag, bdat->imag);
00650
00651 return f_complex_new2(CLASS_OF(self), real, imag);
00652 }
00653 if (k_numeric_p(other) && f_real_p(other)) {
00654 get_dat1(self);
00655
00656 return f_complex_new2(CLASS_OF(self),
00657 (*func)(dat->real, other), dat->imag);
00658 }
00659 return rb_num_coerce_bin(self, other, id);
00660 }
00661
00662
00663
00664
00665
00666
00667
00668 static VALUE
00669 nucomp_add(VALUE self, VALUE other)
00670 {
00671 return f_addsub(self, other, f_add, '+');
00672 }
00673
00674
00675
00676
00677
00678
00679
00680 static VALUE
00681 nucomp_sub(VALUE self, VALUE other)
00682 {
00683 return f_addsub(self, other, f_sub, '-');
00684 }
00685
00686
00687
00688
00689
00690
00691
00692 static VALUE
00693 nucomp_mul(VALUE self, VALUE other)
00694 {
00695 if (k_complex_p(other)) {
00696 VALUE real, imag;
00697
00698 get_dat2(self, other);
00699
00700 real = f_sub(f_mul(adat->real, bdat->real),
00701 f_mul(adat->imag, bdat->imag));
00702 imag = f_add(f_mul(adat->real, bdat->imag),
00703 f_mul(adat->imag, bdat->real));
00704
00705 return f_complex_new2(CLASS_OF(self), real, imag);
00706 }
00707 if (k_numeric_p(other) && f_real_p(other)) {
00708 get_dat1(self);
00709
00710 return f_complex_new2(CLASS_OF(self),
00711 f_mul(dat->real, other),
00712 f_mul(dat->imag, other));
00713 }
00714 return rb_num_coerce_bin(self, other, '*');
00715 }
00716
00717 inline static VALUE
00718 f_divide(VALUE self, VALUE other,
00719 VALUE (*func)(VALUE, VALUE), ID id)
00720 {
00721 if (k_complex_p(other)) {
00722 int flo;
00723 get_dat2(self, other);
00724
00725 flo = (k_float_p(adat->real) || k_float_p(adat->imag) ||
00726 k_float_p(bdat->real) || k_float_p(bdat->imag));
00727
00728 if (f_gt_p(f_abs(bdat->real), f_abs(bdat->imag))) {
00729 VALUE r, n;
00730
00731 r = (*func)(bdat->imag, bdat->real);
00732 n = f_mul(bdat->real, f_add(ONE, f_mul(r, r)));
00733 if (flo)
00734 return f_complex_new2(CLASS_OF(self),
00735 (*func)(self, n),
00736 (*func)(f_negate(f_mul(self, r)), n));
00737 return f_complex_new2(CLASS_OF(self),
00738 (*func)(f_add(adat->real,
00739 f_mul(adat->imag, r)), n),
00740 (*func)(f_sub(adat->imag,
00741 f_mul(adat->real, r)), n));
00742 }
00743 else {
00744 VALUE r, n;
00745
00746 r = (*func)(bdat->real, bdat->imag);
00747 n = f_mul(bdat->imag, f_add(ONE, f_mul(r, r)));
00748 if (flo)
00749 return f_complex_new2(CLASS_OF(self),
00750 (*func)(f_mul(self, r), n),
00751 (*func)(f_negate(self), n));
00752 return f_complex_new2(CLASS_OF(self),
00753 (*func)(f_add(f_mul(adat->real, r),
00754 adat->imag), n),
00755 (*func)(f_sub(f_mul(adat->imag, r),
00756 adat->real), n));
00757 }
00758 }
00759 if (k_numeric_p(other) && f_real_p(other)) {
00760 get_dat1(self);
00761
00762 return f_complex_new2(CLASS_OF(self),
00763 (*func)(dat->real, other),
00764 (*func)(dat->imag, other));
00765 }
00766 return rb_num_coerce_bin(self, other, id);
00767 }
00768
00769 #define rb_raise_zerodiv() rb_raise(rb_eZeroDivError, "divided by 0")
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783 static VALUE
00784 nucomp_div(VALUE self, VALUE other)
00785 {
00786 return f_divide(self, other, f_quo, id_quo);
00787 }
00788
00789 #define nucomp_quo nucomp_div
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801 static VALUE
00802 nucomp_fdiv(VALUE self, VALUE other)
00803 {
00804 return f_divide(self, other, f_fdiv, id_fdiv);
00805 }
00806
00807 inline static VALUE
00808 f_reciprocal(VALUE x)
00809 {
00810 return f_quo(ONE, x);
00811 }
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824 static VALUE
00825 nucomp_expt(VALUE self, VALUE other)
00826 {
00827 if (k_exact_zero_p(other))
00828 return f_complex_new_bang1(CLASS_OF(self), ONE);
00829
00830 if (k_rational_p(other) && f_one_p(f_denominator(other)))
00831 other = f_numerator(other);
00832
00833 if (k_complex_p(other)) {
00834 get_dat1(other);
00835
00836 if (k_exact_zero_p(dat->imag))
00837 other = dat->real;
00838 }
00839
00840 if (k_complex_p(other)) {
00841 VALUE r, theta, nr, ntheta;
00842
00843 get_dat1(other);
00844
00845 r = f_abs(self);
00846 theta = f_arg(self);
00847
00848 nr = m_exp_bang(f_sub(f_mul(dat->real, m_log_bang(r)),
00849 f_mul(dat->imag, theta)));
00850 ntheta = f_add(f_mul(theta, dat->real),
00851 f_mul(dat->imag, m_log_bang(r)));
00852 return f_complex_polar(CLASS_OF(self), nr, ntheta);
00853 }
00854 if (k_fixnum_p(other)) {
00855 if (f_gt_p(other, ZERO)) {
00856 VALUE x, z;
00857 long n;
00858
00859 x = self;
00860 z = x;
00861 n = FIX2LONG(other) - 1;
00862
00863 while (n) {
00864 long q, r;
00865
00866 while (1) {
00867 get_dat1(x);
00868
00869 q = n / 2;
00870 r = n % 2;
00871
00872 if (r)
00873 break;
00874
00875 x = f_complex_new2(CLASS_OF(self),
00876 f_sub(f_mul(dat->real, dat->real),
00877 f_mul(dat->imag, dat->imag)),
00878 f_mul(f_mul(TWO, dat->real), dat->imag));
00879 n = q;
00880 }
00881 z = f_mul(z, x);
00882 n--;
00883 }
00884 return z;
00885 }
00886 return f_expt(f_reciprocal(self), f_negate(other));
00887 }
00888 if (k_numeric_p(other) && f_real_p(other)) {
00889 VALUE r, theta;
00890
00891 if (k_bignum_p(other))
00892 rb_warn("in a**b, b may be too big");
00893
00894 r = f_abs(self);
00895 theta = f_arg(self);
00896
00897 return f_complex_polar(CLASS_OF(self), f_expt(r, other),
00898 f_mul(theta, other));
00899 }
00900 return rb_num_coerce_bin(self, other, id_expt);
00901 }
00902
00903
00904
00905
00906
00907
00908
00909 static VALUE
00910 nucomp_eqeq_p(VALUE self, VALUE other)
00911 {
00912 if (k_complex_p(other)) {
00913 get_dat2(self, other);
00914
00915 return f_boolcast(f_eqeq_p(adat->real, bdat->real) &&
00916 f_eqeq_p(adat->imag, bdat->imag));
00917 }
00918 if (k_numeric_p(other) && f_real_p(other)) {
00919 get_dat1(self);
00920
00921 return f_boolcast(f_eqeq_p(dat->real, other) && f_zero_p(dat->imag));
00922 }
00923 return f_eqeq_p(other, self);
00924 }
00925
00926
00927 static VALUE
00928 nucomp_coerce(VALUE self, VALUE other)
00929 {
00930 if (k_numeric_p(other) && f_real_p(other))
00931 return rb_assoc_new(f_complex_new_bang1(CLASS_OF(self), other), self);
00932 if (TYPE(other) == T_COMPLEX)
00933 return rb_assoc_new(other, self);
00934
00935 rb_raise(rb_eTypeError, "%s can't be coerced into %s",
00936 rb_obj_classname(other), rb_obj_classname(self));
00937 return Qnil;
00938 }
00939
00940
00941
00942
00943
00944
00945
00946
00947 static VALUE
00948 nucomp_abs(VALUE self)
00949 {
00950 get_dat1(self);
00951
00952 if (f_zero_p(dat->real)) {
00953 VALUE a = f_abs(dat->imag);
00954 if (k_float_p(dat->real) && !k_float_p(dat->imag))
00955 a = f_to_f(a);
00956 return a;
00957 }
00958 if (f_zero_p(dat->imag)) {
00959 VALUE a = f_abs(dat->real);
00960 if (!k_float_p(dat->real) && k_float_p(dat->imag))
00961 a = f_to_f(a);
00962 return a;
00963 }
00964 return m_hypot(dat->real, dat->imag);
00965 }
00966
00967
00968
00969
00970
00971
00972
00973 static VALUE
00974 nucomp_abs2(VALUE self)
00975 {
00976 get_dat1(self);
00977 return f_add(f_mul(dat->real, dat->real),
00978 f_mul(dat->imag, dat->imag));
00979 }
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989 static VALUE
00990 nucomp_arg(VALUE self)
00991 {
00992 get_dat1(self);
00993 return m_atan2_bang(dat->imag, dat->real);
00994 }
00995
00996
00997
00998
00999
01000
01001
01002
01003 static VALUE
01004 nucomp_rect(VALUE self)
01005 {
01006 get_dat1(self);
01007 return rb_assoc_new(dat->real, dat->imag);
01008 }
01009
01010
01011
01012
01013
01014
01015
01016 static VALUE
01017 nucomp_polar(VALUE self)
01018 {
01019 return rb_assoc_new(f_abs(self), f_arg(self));
01020 }
01021
01022
01023
01024
01025
01026
01027
01028
01029 static VALUE
01030 nucomp_conj(VALUE self)
01031 {
01032 get_dat1(self);
01033 return f_complex_new2(CLASS_OF(self), dat->real, f_negate(dat->imag));
01034 }
01035
01036 #if 0
01037
01038 static VALUE
01039 nucomp_true(VALUE self)
01040 {
01041 return Qtrue;
01042 }
01043 #endif
01044
01045
01046
01047
01048
01049
01050
01051 static VALUE
01052 nucomp_false(VALUE self)
01053 {
01054 return Qfalse;
01055 }
01056
01057 #if 0
01058
01059 static VALUE
01060 nucomp_exact_p(VALUE self)
01061 {
01062 get_dat1(self);
01063 return f_boolcast(k_exact_p(dat->real) && k_exact_p(dat->imag));
01064 }
01065
01066
01067 static VALUE
01068 nucomp_inexact_p(VALUE self)
01069 {
01070 return f_boolcast(!nucomp_exact_p(self));
01071 }
01072 #endif
01073
01074 extern VALUE rb_lcm(VALUE x, VALUE y);
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084 static VALUE
01085 nucomp_denominator(VALUE self)
01086 {
01087 get_dat1(self);
01088 return rb_lcm(f_denominator(dat->real), f_denominator(dat->imag));
01089 }
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111 static VALUE
01112 nucomp_numerator(VALUE self)
01113 {
01114 VALUE cd;
01115
01116 get_dat1(self);
01117
01118 cd = f_denominator(self);
01119 return f_complex_new2(CLASS_OF(self),
01120 f_mul(f_numerator(dat->real),
01121 f_div(cd, f_denominator(dat->real))),
01122 f_mul(f_numerator(dat->imag),
01123 f_div(cd, f_denominator(dat->imag))));
01124 }
01125
01126
01127 static VALUE
01128 nucomp_hash(VALUE self)
01129 {
01130 st_index_t v, h[2];
01131 VALUE n;
01132
01133 get_dat1(self);
01134 n = rb_hash(dat->real);
01135 h[0] = NUM2LONG(n);
01136 n = rb_hash(dat->imag);
01137 h[1] = NUM2LONG(n);
01138 v = rb_memhash(h, sizeof(h));
01139 return LONG2FIX(v);
01140 }
01141
01142
01143 static VALUE
01144 nucomp_eql_p(VALUE self, VALUE other)
01145 {
01146 if (k_complex_p(other)) {
01147 get_dat2(self, other);
01148
01149 return f_boolcast((CLASS_OF(adat->real) == CLASS_OF(bdat->real)) &&
01150 (CLASS_OF(adat->imag) == CLASS_OF(bdat->imag)) &&
01151 f_eqeq_p(self, other));
01152
01153 }
01154 return Qfalse;
01155 }
01156
01157 inline static VALUE
01158 f_signbit(VALUE x)
01159 {
01160 switch (TYPE(x)) {
01161 case T_FLOAT: {
01162 double f = RFLOAT_VALUE(x);
01163 return f_boolcast(!isnan(f) && signbit(f));
01164 }
01165 }
01166 return f_negative_p(x);
01167 }
01168
01169 inline static VALUE
01170 f_tpositive_p(VALUE x)
01171 {
01172 return f_boolcast(!f_signbit(x));
01173 }
01174
01175 static VALUE
01176 f_format(VALUE self, VALUE (*func)(VALUE))
01177 {
01178 VALUE s, impos;
01179
01180 get_dat1(self);
01181
01182 impos = f_tpositive_p(dat->imag);
01183
01184 s = (*func)(dat->real);
01185 rb_str_cat2(s, !impos ? "-" : "+");
01186
01187 rb_str_concat(s, (*func)(f_abs(dat->imag)));
01188 if (!rb_isdigit(RSTRING_PTR(s)[RSTRING_LEN(s) - 1]))
01189 rb_str_cat2(s, "*");
01190 rb_str_cat2(s, "i");
01191
01192 return s;
01193 }
01194
01195
01196
01197
01198
01199
01200
01201 static VALUE
01202 nucomp_to_s(VALUE self)
01203 {
01204 return f_format(self, f_to_s);
01205 }
01206
01207
01208
01209
01210
01211
01212
01213 static VALUE
01214 nucomp_inspect(VALUE self)
01215 {
01216 VALUE s;
01217
01218 s = rb_usascii_str_new2("(");
01219 rb_str_concat(s, f_format(self, f_inspect));
01220 rb_str_cat2(s, ")");
01221
01222 return s;
01223 }
01224
01225
01226 static VALUE
01227 nucomp_marshal_dump(VALUE self)
01228 {
01229 VALUE a;
01230 get_dat1(self);
01231
01232 a = rb_assoc_new(dat->real, dat->imag);
01233 rb_copy_generic_ivar(a, self);
01234 return a;
01235 }
01236
01237
01238 static VALUE
01239 nucomp_marshal_load(VALUE self, VALUE a)
01240 {
01241 get_dat1(self);
01242 Check_Type(a, T_ARRAY);
01243 dat->real = RARRAY_PTR(a)[0];
01244 dat->imag = RARRAY_PTR(a)[1];
01245 rb_copy_generic_ivar(self, a);
01246 return self;
01247 }
01248
01249
01250
01251 VALUE
01252 rb_complex_raw(VALUE x, VALUE y)
01253 {
01254 return nucomp_s_new_internal(rb_cComplex, x, y);
01255 }
01256
01257 VALUE
01258 rb_complex_new(VALUE x, VALUE y)
01259 {
01260 return nucomp_s_canonicalize_internal(rb_cComplex, x, y);
01261 }
01262
01263 VALUE
01264 rb_complex_polar(VALUE x, VALUE y)
01265 {
01266 return f_complex_polar(rb_cComplex, x, y);
01267 }
01268
01269 static VALUE nucomp_s_convert(int argc, VALUE *argv, VALUE klass);
01270
01271 VALUE
01272 rb_Complex(VALUE x, VALUE y)
01273 {
01274 VALUE a[2];
01275 a[0] = x;
01276 a[1] = y;
01277 return nucomp_s_convert(2, a, rb_cComplex);
01278 }
01279
01280
01281
01282
01283
01284
01285
01286 static VALUE
01287 nucomp_to_i(VALUE self)
01288 {
01289 get_dat1(self);
01290
01291 if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) {
01292 VALUE s = f_to_s(self);
01293 rb_raise(rb_eRangeError, "can't convert %s into Integer",
01294 StringValuePtr(s));
01295 }
01296 return f_to_i(dat->real);
01297 }
01298
01299
01300
01301
01302
01303
01304
01305 static VALUE
01306 nucomp_to_f(VALUE self)
01307 {
01308 get_dat1(self);
01309
01310 if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) {
01311 VALUE s = f_to_s(self);
01312 rb_raise(rb_eRangeError, "can't convert %s into Float",
01313 StringValuePtr(s));
01314 }
01315 return f_to_f(dat->real);
01316 }
01317
01318
01319
01320
01321
01322
01323
01324 static VALUE
01325 nucomp_to_r(VALUE self)
01326 {
01327 get_dat1(self);
01328
01329 if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) {
01330 VALUE s = f_to_s(self);
01331 rb_raise(rb_eRangeError, "can't convert %s into Rational",
01332 StringValuePtr(s));
01333 }
01334 return f_to_r(dat->real);
01335 }
01336
01337
01338
01339
01340
01341
01342
01343
01344 static VALUE
01345 nucomp_rationalize(int argc, VALUE *argv, VALUE self)
01346 {
01347 rb_scan_args(argc, argv, "01", NULL);
01348 return nucomp_to_r(self);
01349 }
01350
01351
01352
01353
01354
01355
01356
01357 static VALUE
01358 nilclass_to_c(VALUE self)
01359 {
01360 return rb_complex_new1(INT2FIX(0));
01361 }
01362
01363
01364
01365
01366
01367
01368
01369 static VALUE
01370 numeric_to_c(VALUE self)
01371 {
01372 return rb_complex_new1(self);
01373 }
01374
01375 static VALUE comp_pat0, comp_pat1, comp_pat2, a_slash, a_dot_and_an_e,
01376 null_string, underscores_pat, an_underscore;
01377
01378 #define WS "\\s*"
01379 #define DIGITS "(?:[0-9](?:_[0-9]|[0-9])*)"
01380 #define NUMERATOR "(?:" DIGITS "?\\.)?" DIGITS "(?:[eE][-+]?" DIGITS ")?"
01381 #define DENOMINATOR DIGITS
01382 #define NUMBER "[-+]?" NUMERATOR "(?:\\/" DENOMINATOR ")?"
01383 #define NUMBERNOS NUMERATOR "(?:\\/" DENOMINATOR ")?"
01384 #define PATTERN0 "\\A" WS "(" NUMBER ")@(" NUMBER ")" WS
01385 #define PATTERN1 "\\A" WS "([-+])?(" NUMBER ")?[iIjJ]" WS
01386 #define PATTERN2 "\\A" WS "(" NUMBER ")(([-+])(" NUMBERNOS ")?[iIjJ])?" WS
01387
01388 static void
01389 make_patterns(void)
01390 {
01391 static const char comp_pat0_source[] = PATTERN0;
01392 static const char comp_pat1_source[] = PATTERN1;
01393 static const char comp_pat2_source[] = PATTERN2;
01394 static const char underscores_pat_source[] = "_+";
01395
01396 if (comp_pat0) return;
01397
01398 comp_pat0 = rb_reg_new(comp_pat0_source, sizeof comp_pat0_source - 1, 0);
01399 rb_gc_register_mark_object(comp_pat0);
01400
01401 comp_pat1 = rb_reg_new(comp_pat1_source, sizeof comp_pat1_source - 1, 0);
01402 rb_gc_register_mark_object(comp_pat1);
01403
01404 comp_pat2 = rb_reg_new(comp_pat2_source, sizeof comp_pat2_source - 1, 0);
01405 rb_gc_register_mark_object(comp_pat2);
01406
01407 a_slash = rb_usascii_str_new2("/");
01408 rb_gc_register_mark_object(a_slash);
01409
01410 a_dot_and_an_e = rb_usascii_str_new2(".eE");
01411 rb_gc_register_mark_object(a_dot_and_an_e);
01412
01413 null_string = rb_usascii_str_new2("");
01414 rb_gc_register_mark_object(null_string);
01415
01416 underscores_pat = rb_reg_new(underscores_pat_source,
01417 sizeof underscores_pat_source - 1, 0);
01418 rb_gc_register_mark_object(underscores_pat);
01419
01420 an_underscore = rb_usascii_str_new2("_");
01421 rb_gc_register_mark_object(an_underscore);
01422 }
01423
01424 #define id_match rb_intern("match")
01425 #define f_match(x,y) rb_funcall(x, id_match, 1, y)
01426
01427 #define id_aref rb_intern("[]")
01428 #define f_aref(x,y) rb_funcall(x, id_aref, 1, y)
01429
01430 #define id_post_match rb_intern("post_match")
01431 #define f_post_match(x) rb_funcall(x, id_post_match, 0)
01432
01433 #define id_split rb_intern("split")
01434 #define f_split(x,y) rb_funcall(x, id_split, 1, y)
01435
01436 #define id_include_p rb_intern("include?")
01437 #define f_include_p(x,y) rb_funcall(x, id_include_p, 1, y)
01438
01439 #define id_count rb_intern("count")
01440 #define f_count(x,y) rb_funcall(x, id_count, 1, y)
01441
01442 #define id_gsub_bang rb_intern("gsub!")
01443 #define f_gsub_bang(x,y,z) rb_funcall(x, id_gsub_bang, 2, y, z)
01444
01445 static VALUE
01446 string_to_c_internal(VALUE self)
01447 {
01448 VALUE s;
01449
01450 s = self;
01451
01452 if (RSTRING_LEN(s) == 0)
01453 return rb_assoc_new(Qnil, self);
01454
01455 {
01456 VALUE m, sr, si, re, r, i;
01457 int po;
01458
01459 m = f_match(comp_pat0, s);
01460 if (!NIL_P(m)) {
01461 sr = f_aref(m, INT2FIX(1));
01462 si = f_aref(m, INT2FIX(2));
01463 re = f_post_match(m);
01464 po = 1;
01465 }
01466 if (NIL_P(m)) {
01467 m = f_match(comp_pat1, s);
01468 if (!NIL_P(m)) {
01469 sr = Qnil;
01470 si = f_aref(m, INT2FIX(1));
01471 if (NIL_P(si))
01472 si = rb_usascii_str_new2("");
01473 {
01474 VALUE t;
01475
01476 t = f_aref(m, INT2FIX(2));
01477 if (NIL_P(t))
01478 t = rb_usascii_str_new2("1");
01479 rb_str_concat(si, t);
01480 }
01481 re = f_post_match(m);
01482 po = 0;
01483 }
01484 }
01485 if (NIL_P(m)) {
01486 m = f_match(comp_pat2, s);
01487 if (NIL_P(m))
01488 return rb_assoc_new(Qnil, self);
01489 sr = f_aref(m, INT2FIX(1));
01490 if (NIL_P(f_aref(m, INT2FIX(2))))
01491 si = Qnil;
01492 else {
01493 VALUE t;
01494
01495 si = f_aref(m, INT2FIX(3));
01496 t = f_aref(m, INT2FIX(4));
01497 if (NIL_P(t))
01498 t = rb_usascii_str_new2("1");
01499 rb_str_concat(si, t);
01500 }
01501 re = f_post_match(m);
01502 po = 0;
01503 }
01504 r = INT2FIX(0);
01505 i = INT2FIX(0);
01506 if (!NIL_P(sr)) {
01507 if (f_include_p(sr, a_slash))
01508 r = f_to_r(sr);
01509 else if (f_gt_p(f_count(sr, a_dot_and_an_e), INT2FIX(0)))
01510 r = f_to_f(sr);
01511 else
01512 r = f_to_i(sr);
01513 }
01514 if (!NIL_P(si)) {
01515 if (f_include_p(si, a_slash))
01516 i = f_to_r(si);
01517 else if (f_gt_p(f_count(si, a_dot_and_an_e), INT2FIX(0)))
01518 i = f_to_f(si);
01519 else
01520 i = f_to_i(si);
01521 }
01522 if (po)
01523 return rb_assoc_new(rb_complex_polar(r, i), re);
01524 else
01525 return rb_assoc_new(rb_complex_new2(r, i), re);
01526 }
01527 }
01528
01529 static VALUE
01530 string_to_c_strict(VALUE self)
01531 {
01532 VALUE a = string_to_c_internal(self);
01533 if (NIL_P(RARRAY_PTR(a)[0]) || RSTRING_LEN(RARRAY_PTR(a)[1]) > 0) {
01534 VALUE s = f_inspect(self);
01535 rb_raise(rb_eArgError, "invalid value for convert(): %s",
01536 StringValuePtr(s));
01537 }
01538 return RARRAY_PTR(a)[0];
01539 }
01540
01541 #define id_gsub rb_intern("gsub")
01542 #define f_gsub(x,y,z) rb_funcall(x, id_gsub, 2, y, z)
01543
01544
01545
01546
01547
01548
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567 static VALUE
01568 string_to_c(VALUE self)
01569 {
01570 VALUE s, a, backref;
01571
01572 backref = rb_backref_get();
01573 rb_match_busy(backref);
01574
01575 s = f_gsub(self, underscores_pat, an_underscore);
01576 a = string_to_c_internal(s);
01577
01578 rb_backref_set(backref);
01579
01580 if (!NIL_P(RARRAY_PTR(a)[0]))
01581 return RARRAY_PTR(a)[0];
01582 return rb_complex_new1(INT2FIX(0));
01583 }
01584
01585 static VALUE
01586 nucomp_s_convert(int argc, VALUE *argv, VALUE klass)
01587 {
01588 VALUE a1, a2, backref;
01589
01590 rb_scan_args(argc, argv, "11", &a1, &a2);
01591
01592 if (NIL_P(a1) || (argc == 2 && NIL_P(a2)))
01593 rb_raise(rb_eTypeError, "can't convert nil into Complex");
01594
01595 backref = rb_backref_get();
01596 rb_match_busy(backref);
01597
01598 switch (TYPE(a1)) {
01599 case T_FIXNUM:
01600 case T_BIGNUM:
01601 case T_FLOAT:
01602 break;
01603 case T_STRING:
01604 a1 = string_to_c_strict(a1);
01605 break;
01606 }
01607
01608 switch (TYPE(a2)) {
01609 case T_FIXNUM:
01610 case T_BIGNUM:
01611 case T_FLOAT:
01612 break;
01613 case T_STRING:
01614 a2 = string_to_c_strict(a2);
01615 break;
01616 }
01617
01618 rb_backref_set(backref);
01619
01620 switch (TYPE(a1)) {
01621 case T_COMPLEX:
01622 {
01623 get_dat1(a1);
01624
01625 if (k_exact_zero_p(dat->imag))
01626 a1 = dat->real;
01627 }
01628 }
01629
01630 switch (TYPE(a2)) {
01631 case T_COMPLEX:
01632 {
01633 get_dat1(a2);
01634
01635 if (k_exact_zero_p(dat->imag))
01636 a2 = dat->real;
01637 }
01638 }
01639
01640 switch (TYPE(a1)) {
01641 case T_COMPLEX:
01642 if (argc == 1 || (k_exact_zero_p(a2)))
01643 return a1;
01644 }
01645
01646 if (argc == 1) {
01647 if (k_numeric_p(a1) && !f_real_p(a1))
01648 return a1;
01649
01650 if (!k_numeric_p(a1))
01651 return rb_convert_type(a1, T_COMPLEX, "Complex", "to_c");
01652 }
01653 else {
01654 if ((k_numeric_p(a1) && k_numeric_p(a2)) &&
01655 (!f_real_p(a1) || !f_real_p(a2)))
01656 return f_add(a1,
01657 f_mul(a2,
01658 f_complex_new_bang2(rb_cComplex, ZERO, ONE)));
01659 }
01660
01661 {
01662 VALUE argv2[2];
01663 argv2[0] = a1;
01664 argv2[1] = a2;
01665 return nucomp_s_new(argc, argv2, klass);
01666 }
01667 }
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677 static VALUE
01678 numeric_real(VALUE self)
01679 {
01680 return self;
01681 }
01682
01683
01684
01685
01686
01687
01688
01689
01690 static VALUE
01691 numeric_imag(VALUE self)
01692 {
01693 return INT2FIX(0);
01694 }
01695
01696
01697
01698
01699
01700
01701
01702 static VALUE
01703 numeric_abs2(VALUE self)
01704 {
01705 return f_mul(self, self);
01706 }
01707
01708 #define id_PI rb_intern("PI")
01709
01710
01711
01712
01713
01714
01715
01716
01717
01718 static VALUE
01719 numeric_arg(VALUE self)
01720 {
01721 if (f_positive_p(self))
01722 return INT2FIX(0);
01723 return rb_const_get(rb_mMath, id_PI);
01724 }
01725
01726
01727
01728
01729
01730
01731
01732 static VALUE
01733 numeric_rect(VALUE self)
01734 {
01735 return rb_assoc_new(self, INT2FIX(0));
01736 }
01737
01738
01739
01740
01741
01742
01743
01744 static VALUE
01745 numeric_polar(VALUE self)
01746 {
01747 return rb_assoc_new(f_abs(self), f_arg(self));
01748 }
01749
01750
01751
01752
01753
01754
01755
01756
01757 static VALUE
01758 numeric_conj(VALUE self)
01759 {
01760 return self;
01761 }
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771 static VALUE
01772 float_arg(VALUE self)
01773 {
01774 if (isnan(RFLOAT_VALUE(self)))
01775 return self;
01776 if (f_tpositive_p(self))
01777 return INT2FIX(0);
01778 return rb_const_get(rb_mMath, id_PI);
01779 }
01780
01781
01782
01783
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
01810
01811
01812
01813 void
01814 Init_Complex(void)
01815 {
01816 #undef rb_intern
01817 #define rb_intern(str) rb_intern_const(str)
01818
01819 assert(fprintf(stderr, "assert() is now active\n"));
01820
01821 id_abs = rb_intern("abs");
01822 id_abs2 = rb_intern("abs2");
01823 id_arg = rb_intern("arg");
01824 id_cmp = rb_intern("<=>");
01825 id_conj = rb_intern("conj");
01826 id_convert = rb_intern("convert");
01827 id_denominator = rb_intern("denominator");
01828 id_divmod = rb_intern("divmod");
01829 id_eqeq_p = rb_intern("==");
01830 id_expt = rb_intern("**");
01831 id_fdiv = rb_intern("fdiv");
01832 id_floor = rb_intern("floor");
01833 id_idiv = rb_intern("div");
01834 id_imag = rb_intern("imag");
01835 id_inspect = rb_intern("inspect");
01836 id_negate = rb_intern("-@");
01837 id_numerator = rb_intern("numerator");
01838 id_quo = rb_intern("quo");
01839 id_real = rb_intern("real");
01840 id_real_p = rb_intern("real?");
01841 id_to_f = rb_intern("to_f");
01842 id_to_i = rb_intern("to_i");
01843 id_to_r = rb_intern("to_r");
01844 id_to_s = rb_intern("to_s");
01845
01846 rb_cComplex = rb_define_class("Complex", rb_cNumeric);
01847
01848 rb_define_alloc_func(rb_cComplex, nucomp_s_alloc);
01849 rb_undef_method(CLASS_OF(rb_cComplex), "allocate");
01850
01851 #if 0
01852 rb_define_private_method(CLASS_OF(rb_cComplex), "new!", nucomp_s_new_bang, -1);
01853 rb_define_private_method(CLASS_OF(rb_cComplex), "new", nucomp_s_new, -1);
01854 #else
01855 rb_undef_method(CLASS_OF(rb_cComplex), "new");
01856 #endif
01857
01858 rb_define_singleton_method(rb_cComplex, "rectangular", nucomp_s_new, -1);
01859 rb_define_singleton_method(rb_cComplex, "rect", nucomp_s_new, -1);
01860 rb_define_singleton_method(rb_cComplex, "polar", nucomp_s_polar, -1);
01861
01862 rb_define_global_function("Complex", nucomp_f_complex, -1);
01863
01864 rb_undef_method(rb_cComplex, "%");
01865 rb_undef_method(rb_cComplex, "<");
01866 rb_undef_method(rb_cComplex, "<=");
01867 rb_undef_method(rb_cComplex, "<=>");
01868 rb_undef_method(rb_cComplex, ">");
01869 rb_undef_method(rb_cComplex, ">=");
01870 rb_undef_method(rb_cComplex, "between?");
01871 rb_undef_method(rb_cComplex, "div");
01872 rb_undef_method(rb_cComplex, "divmod");
01873 rb_undef_method(rb_cComplex, "floor");
01874 rb_undef_method(rb_cComplex, "ceil");
01875 rb_undef_method(rb_cComplex, "modulo");
01876 rb_undef_method(rb_cComplex, "remainder");
01877 rb_undef_method(rb_cComplex, "round");
01878 rb_undef_method(rb_cComplex, "step");
01879 rb_undef_method(rb_cComplex, "truncate");
01880 rb_undef_method(rb_cComplex, "i");
01881
01882 #if 0
01883 rb_undef_method(rb_cComplex, "//");
01884 #endif
01885
01886 rb_define_method(rb_cComplex, "real", nucomp_real, 0);
01887 rb_define_method(rb_cComplex, "imaginary", nucomp_imag, 0);
01888 rb_define_method(rb_cComplex, "imag", nucomp_imag, 0);
01889
01890 rb_define_method(rb_cComplex, "-@", nucomp_negate, 0);
01891 rb_define_method(rb_cComplex, "+", nucomp_add, 1);
01892 rb_define_method(rb_cComplex, "-", nucomp_sub, 1);
01893 rb_define_method(rb_cComplex, "*", nucomp_mul, 1);
01894 rb_define_method(rb_cComplex, "/", nucomp_div, 1);
01895 rb_define_method(rb_cComplex, "quo", nucomp_quo, 1);
01896 rb_define_method(rb_cComplex, "fdiv", nucomp_fdiv, 1);
01897 rb_define_method(rb_cComplex, "**", nucomp_expt, 1);
01898
01899 rb_define_method(rb_cComplex, "==", nucomp_eqeq_p, 1);
01900 rb_define_method(rb_cComplex, "coerce", nucomp_coerce, 1);
01901
01902 rb_define_method(rb_cComplex, "abs", nucomp_abs, 0);
01903 rb_define_method(rb_cComplex, "magnitude", nucomp_abs, 0);
01904 rb_define_method(rb_cComplex, "abs2", nucomp_abs2, 0);
01905 rb_define_method(rb_cComplex, "arg", nucomp_arg, 0);
01906 rb_define_method(rb_cComplex, "angle", nucomp_arg, 0);
01907 rb_define_method(rb_cComplex, "phase", nucomp_arg, 0);
01908 rb_define_method(rb_cComplex, "rectangular", nucomp_rect, 0);
01909 rb_define_method(rb_cComplex, "rect", nucomp_rect, 0);
01910 rb_define_method(rb_cComplex, "polar", nucomp_polar, 0);
01911 rb_define_method(rb_cComplex, "conjugate", nucomp_conj, 0);
01912 rb_define_method(rb_cComplex, "conj", nucomp_conj, 0);
01913 #if 0
01914 rb_define_method(rb_cComplex, "~", nucomp_conj, 0);
01915 #endif
01916
01917 rb_define_method(rb_cComplex, "real?", nucomp_false, 0);
01918 #if 0
01919 rb_define_method(rb_cComplex, "complex?", nucomp_true, 0);
01920 rb_define_method(rb_cComplex, "exact?", nucomp_exact_p, 0);
01921 rb_define_method(rb_cComplex, "inexact?", nucomp_inexact_p, 0);
01922 #endif
01923
01924 rb_define_method(rb_cComplex, "numerator", nucomp_numerator, 0);
01925 rb_define_method(rb_cComplex, "denominator", nucomp_denominator, 0);
01926
01927 rb_define_method(rb_cComplex, "hash", nucomp_hash, 0);
01928 rb_define_method(rb_cComplex, "eql?", nucomp_eql_p, 1);
01929
01930 rb_define_method(rb_cComplex, "to_s", nucomp_to_s, 0);
01931 rb_define_method(rb_cComplex, "inspect", nucomp_inspect, 0);
01932
01933 rb_define_method(rb_cComplex, "marshal_dump", nucomp_marshal_dump, 0);
01934 rb_define_method(rb_cComplex, "marshal_load", nucomp_marshal_load, 1);
01935
01936
01937
01938 rb_define_method(rb_cComplex, "to_i", nucomp_to_i, 0);
01939 rb_define_method(rb_cComplex, "to_f", nucomp_to_f, 0);
01940 rb_define_method(rb_cComplex, "to_r", nucomp_to_r, 0);
01941 rb_define_method(rb_cComplex, "rationalize", nucomp_rationalize, -1);
01942 rb_define_method(rb_cNilClass, "to_c", nilclass_to_c, 0);
01943 rb_define_method(rb_cNumeric, "to_c", numeric_to_c, 0);
01944
01945 make_patterns();
01946
01947 rb_define_method(rb_cString, "to_c", string_to_c, 0);
01948
01949 rb_define_private_method(CLASS_OF(rb_cComplex), "convert", nucomp_s_convert, -1);
01950
01951
01952
01953 rb_define_method(rb_cNumeric, "real", numeric_real, 0);
01954 rb_define_method(rb_cNumeric, "imaginary", numeric_imag, 0);
01955 rb_define_method(rb_cNumeric, "imag", numeric_imag, 0);
01956 rb_define_method(rb_cNumeric, "abs2", numeric_abs2, 0);
01957 rb_define_method(rb_cNumeric, "arg", numeric_arg, 0);
01958 rb_define_method(rb_cNumeric, "angle", numeric_arg, 0);
01959 rb_define_method(rb_cNumeric, "phase", numeric_arg, 0);
01960 rb_define_method(rb_cNumeric, "rectangular", numeric_rect, 0);
01961 rb_define_method(rb_cNumeric, "rect", numeric_rect, 0);
01962 rb_define_method(rb_cNumeric, "polar", numeric_polar, 0);
01963 rb_define_method(rb_cNumeric, "conjugate", numeric_conj, 0);
01964 rb_define_method(rb_cNumeric, "conj", numeric_conj, 0);
01965
01966 rb_define_method(rb_cFloat, "arg", float_arg, 0);
01967 rb_define_method(rb_cFloat, "angle", float_arg, 0);
01968 rb_define_method(rb_cFloat, "phase", float_arg, 0);
01969
01970 rb_define_const(rb_cComplex, "I",
01971 f_complex_new_bang2(rb_cComplex, ZERO, ONE));
01972 }
01973
01974
01975
01976
01977
01978
01979