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