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