|
Ruby 1.9.2p290(2011-07-09revision32553)
|
00001 /* 00002 complex.c: Coded by Tadayoshi Funaba 2008,2009 00003 00004 This implementation is based on Keiju Ishitsuka's Complex library 00005 which is written in ruby. 00006 */ 00007 00008 #include "ruby.h" 00009 #include <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 * call-seq: 00424 * Complex.rect(real[, imag]) -> complex 00425 * Complex.rectangular(real[, imag]) -> complex 00426 * 00427 * Returns a complex object which denotes the given rectangular form. 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 * call-seq: 00464 * Complex(x[, y]) -> numeric 00465 * 00466 * Returns x+i*y; 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 * call-seq: 00576 * Complex.polar(abs[, arg]) -> complex 00577 * 00578 * Returns a complex object which denotes the given polar form. 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 * call-seq: 00600 * cmp.real -> real 00601 * 00602 * Returns the real part. 00603 */ 00604 static VALUE 00605 nucomp_real(VALUE self) 00606 { 00607 get_dat1(self); 00608 return dat->real; 00609 } 00610 00611 /* 00612 * call-seq: 00613 * cmp.imag -> real 00614 * cmp.imaginary -> real 00615 * 00616 * Returns the imaginary part. 00617 */ 00618 static VALUE 00619 nucomp_imag(VALUE self) 00620 { 00621 get_dat1(self); 00622 return dat->imag; 00623 } 00624 00625 /* 00626 * call-seq: 00627 * -cmp -> complex 00628 * 00629 * Returns negation of the value. 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 * call-seq: 00664 * cmp + numeric -> complex 00665 * 00666 * Performs addition. 00667 */ 00668 static VALUE 00669 nucomp_add(VALUE self, VALUE other) 00670 { 00671 return f_addsub(self, other, f_add, '+'); 00672 } 00673 00674 /* 00675 * call-seq: 00676 * cmp - numeric -> complex 00677 * 00678 * Performs subtraction. 00679 */ 00680 static VALUE 00681 nucomp_sub(VALUE self, VALUE other) 00682 { 00683 return f_addsub(self, other, f_sub, '-'); 00684 } 00685 00686 /* 00687 * call-seq: 00688 * cmp * numeric -> complex 00689 * 00690 * Performs multiplication. 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 * call-seq: 00773 * cmp / numeric -> complex 00774 * cmp.quo(numeric) -> complex 00775 * 00776 * Performs division. 00777 * 00778 * For example: 00779 * 00780 * Complex(10.0) / 3 #=> (3.3333333333333335+(0/1)*i) 00781 * Complex(10) / 3 #=> ((10/3)+(0/1)*i) # not (3+0i) 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 * call-seq: 00793 * cmp.fdiv(numeric) -> complex 00794 * 00795 * Performs division as each part is a float, never returns a float. 00796 * 00797 * For example: 00798 * 00799 * Complex(11,22).fdiv(3) #=> (3.6666666666666665+7.333333333333333i) 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 * call-seq: 00815 * cmp ** numeric -> complex 00816 * 00817 * Performs exponentiation. 00818 * 00819 * For example: 00820 * 00821 * Complex('i') ** 2 #=> (-1+0i) 00822 * Complex(-8) ** Rational(1,3) #=> (1.0000000000000002+1.7320508075688772i) 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); /* c14n */ 00832 00833 if (k_complex_p(other)) { 00834 get_dat1(other); 00835 00836 if (k_exact_zero_p(dat->imag)) 00837 other = dat->real; /* c14n */ 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 * call-seq: 00905 * cmp == object -> true or false 00906 * 00907 * Returns true if cmp equals object numerically. 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 /* :nodoc: */ 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 * call-seq: 00942 * cmp.abs -> real 00943 * cmp.magnitude -> real 00944 * 00945 * Returns the absolute part of its polar form. 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 * call-seq: 00969 * cmp.abs2 -> real 00970 * 00971 * Returns square of the absolute value. 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 * call-seq: 00983 * cmp.arg -> float 00984 * cmp.angle -> float 00985 * cmp.phase -> float 00986 * 00987 * Returns the angle part of its polar form. 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 * call-seq: 00998 * cmp.rect -> array 00999 * cmp.rectangular -> array 01000 * 01001 * Returns an array; [cmp.real, cmp.imag]. 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 * call-seq: 01012 * cmp.polar -> array 01013 * 01014 * Returns an array; [cmp.abs, cmp.arg]. 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 * call-seq: 01024 * cmp.conj -> complex 01025 * cmp.conjugate -> complex 01026 * 01027 * Returns the complex conjugate. 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 /* :nodoc: */ 01038 static VALUE 01039 nucomp_true(VALUE self) 01040 { 01041 return Qtrue; 01042 } 01043 #endif 01044 01045 /* 01046 * call-seq: 01047 * cmp.real? -> false 01048 * 01049 * Returns false. 01050 */ 01051 static VALUE 01052 nucomp_false(VALUE self) 01053 { 01054 return Qfalse; 01055 } 01056 01057 #if 0 01058 /* :nodoc: */ 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 /* :nodoc: */ 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 * call-seq: 01078 * cmp.denominator -> integer 01079 * 01080 * Returns the denominator (lcm of both denominator, real and imag). 01081 * 01082 * See numerator. 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 * call-seq: 01093 * cmp.numerator -> numeric 01094 * 01095 * Returns the numerator. 01096 * 01097 * For example: 01098 * 01099 * 1 2 3+4i <- numerator 01100 * - + -i -> ---- 01101 * 2 3 6 <- denominator 01102 * 01103 * c = Complex('1/2+2/3i') #=> ((1/2)+(2/3)*i) 01104 * n = c.numerator #=> (3+4i) 01105 * d = c.denominator #=> 6 01106 * n / d #=> ((1/2)+(2/3)*i) 01107 * Complex(Rational(n.real, d), Rational(n.imag, d)) 01108 * #=> ((1/2)+(2/3)*i) 01109 * See denominator. 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 /* :nodoc: */ 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 /* :nodoc: */ 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 * call-seq: 01197 * cmp.to_s -> string 01198 * 01199 * Returns the value as a string. 01200 */ 01201 static VALUE 01202 nucomp_to_s(VALUE self) 01203 { 01204 return f_format(self, f_to_s); 01205 } 01206 01207 /* 01208 * call-seq: 01209 * cmp.inspect -> string 01210 * 01211 * Returns the value as a string for inspection. 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 /* :nodoc: */ 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 /* :nodoc: */ 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 * call-seq: 01282 * cmp.to_i -> integer 01283 * 01284 * Returns the value as an integer if possible. 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 * call-seq: 01301 * cmp.to_f -> float 01302 * 01303 * Returns the value as a float if possible. 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 * call-seq: 01320 * cmp.to_r -> rational 01321 * 01322 * Returns the value as a rational if possible. 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 * call-seq: 01339 * cmp.rationalize([eps]) -> rational 01340 * 01341 * Returns the value as a rational if possible. An optional argument 01342 * eps is always ignored. 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 * call-seq: 01353 * nil.to_c -> (0+0i) 01354 * 01355 * Returns zero as a complex. 01356 */ 01357 static VALUE 01358 nilclass_to_c(VALUE self) 01359 { 01360 return rb_complex_new1(INT2FIX(0)); 01361 } 01362 01363 /* 01364 * call-seq: 01365 * num.to_c -> complex 01366 * 01367 * Returns the value as a complex. 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 * call-seq: 01546 * str.to_c -> complex 01547 * 01548 * Returns a complex which denotes the string form. The parser 01549 * ignores leading whitespaces and trailing garbage. Any digit 01550 * sequences can be separated by an underscore. Returns zero for null 01551 * or garbage string. 01552 * 01553 * For example: 01554 * 01555 * '9'.to_c #=> (9+0i) 01556 * '2.5'.to_c #=> (2.5+0i) 01557 * '2.5/1'.to_c #=> ((5/2)+0i) 01558 * '-3/2'.to_c #=> ((-3/2)+0i) 01559 * '-i'.to_c #=> (0-1i) 01560 * '45i'.to_c #=> (0+45i) 01561 * '3-4i'.to_c #=> (3-4i) 01562 * '-4e2-4e-2i'.to_c #=> (-400.0-0.04i) 01563 * '-0.0-0.0i'.to_c #=> (-0.0-0.0i) 01564 * '1/2+3/4i'.to_c #=> ((1/2)+(3/4)*i) 01565 * 'ruby'.to_c #=> (0+0i) 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 /* expect raise exception for consistency */ 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 * call-seq: 01673 * num.real -> self 01674 * 01675 * Returns self. 01676 */ 01677 static VALUE 01678 numeric_real(VALUE self) 01679 { 01680 return self; 01681 } 01682 01683 /* 01684 * call-seq: 01685 * num.imag -> 0 01686 * num.imaginary -> 0 01687 * 01688 * Returns zero. 01689 */ 01690 static VALUE 01691 numeric_imag(VALUE self) 01692 { 01693 return INT2FIX(0); 01694 } 01695 01696 /* 01697 * call-seq: 01698 * num.abs2 -> real 01699 * 01700 * Returns square of self. 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 * call-seq: 01712 * num.arg -> 0 or float 01713 * num.angle -> 0 or float 01714 * num.phase -> 0 or float 01715 * 01716 * Returns 0 if the value is positive, pi otherwise. 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 * call-seq: 01728 * num.rect -> array 01729 * 01730 * Returns an array; [num, 0]. 01731 */ 01732 static VALUE 01733 numeric_rect(VALUE self) 01734 { 01735 return rb_assoc_new(self, INT2FIX(0)); 01736 } 01737 01738 /* 01739 * call-seq: 01740 * num.polar -> array 01741 * 01742 * Returns an array; [num.abs, num.arg]. 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 * call-seq: 01752 * num.conj -> self 01753 * num.conjugate -> self 01754 * 01755 * Returns self. 01756 */ 01757 static VALUE 01758 numeric_conj(VALUE self) 01759 { 01760 return self; 01761 } 01762 01763 /* 01764 * call-seq: 01765 * flo.arg -> 0 or float 01766 * flo.angle -> 0 or float 01767 * flo.phase -> 0 or float 01768 * 01769 * Returns 0 if the value is positive, pi otherwise. 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 * A complex number can be represented as a paired real number with 01783 * imaginary unit; a+bi. Where a is real part, b is imaginary part 01784 * and i is imaginary unit. Real a equals complex a+0i 01785 * mathematically. 01786 * 01787 * In ruby, you can create complex object with Complex, Complex::rect, 01788 * Complex::polar or to_c method. 01789 * 01790 * Complex(1) #=> (1+0i) 01791 * Complex(2, 3) #=> (2+3i) 01792 * Complex.polar(2, 3) #=> (-1.9799849932008908+0.2822400161197344i) 01793 * 3.to_c #=> (3+0i) 01794 * 01795 * You can also create complex object from floating-point numbers or 01796 * strings. 01797 * 01798 * Complex(0.3) #=> (0.3+0i) 01799 * Complex('0.3-0.5i') #=> (0.3-0.5i) 01800 * Complex('2/3+3/4i') #=> ((2/3)+(3/4)*i) 01801 * Complex('1@2') #=> (-0.4161468365471424+0.9092974268256817i) 01802 * 01803 * 0.3.to_c #=> (0.3+0i) 01804 * '0.3-0.5i'.to_c #=> (0.3-0.5i) 01805 * '2/3+3/4i'.to_c #=> ((2/3)+(3/4)*i) 01806 * '1@2'.to_c #=> (-0.4161468365471424+0.9092974268256817i) 01807 * 01808 * A complex object is either an exact or an inexact number. 01809 * 01810 * Complex(1, 1) / 2 #=> ((1/2)+(1/2)*i) 01811 * Complex(1, 1) / 2.0 #=> (0.5+0.5i) 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 /* NUBY */ 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); /* gcc */ 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 Local variables: 01976 c-file-style: "ruby" 01977 End: 01978 */ 01979
1.7.3