2 complex.c: Coded by Tadayoshi Funaba 2008-2012
4 This implementation is based on Keiju Ishitsuka's Complex library
5 which is written in ruby.
8 #include "ruby/internal/config.h"
11 /* Microsoft Visual C does not define M_PI and others by default */
12 # define _USE_MATH_DEFINES 1
20 #include "internal/array.h"
21 #include "internal/class.h"
22 #include "internal/complex.h"
23 #include "internal/math.h"
24 #include "internal/numeric.h"
25 #include "internal/object.h"
26 #include "internal/rational.h"
27 #include "ruby_assert.h"
29 #define ZERO INT2FIX(0)
30 #define ONE INT2FIX(1)
31 #define TWO INT2FIX(2)
33 #define RFLOAT_0 DBL2NUM(0)
35 static VALUE RFLOAT_0
;
40 static ID id_abs
, id_arg
,
41 id_denominator
, id_numerator
,
42 id_real_p
, id_i_real
, id_i_imag
,
43 id_finite_p
, id_infinite_p
, id_rationalize
,
45 #define id_to_i idTo_i
46 #define id_to_r idTo_r
47 #define id_negate idUMinus
49 #define id_to_f idTo_f
51 #define id_fdiv idFdiv
57 return rb_funcall(x, id_##n, 0);\
62 f_##n(VALUE x, VALUE y)\
64 return rb_funcall(x, id_##n, 1, y);\
67 #define PRESERVE_SIGNEDZERO
70 f_add(VALUE x
, VALUE y
)
72 if (RB_INTEGER_TYPE_P(x
) &&
73 LIKELY(rb_method_basic_definition_p(rb_cInteger
, idPLUS
))) {
78 return rb_int_plus(x
, y
);
80 else if (RB_FLOAT_TYPE_P(x
) &&
81 LIKELY(rb_method_basic_definition_p(rb_cFloat
, idPLUS
))) {
84 return rb_float_plus(x
, y
);
86 else if (RB_TYPE_P(x
, T_RATIONAL
) &&
87 LIKELY(rb_method_basic_definition_p(rb_cRational
, idPLUS
))) {
90 return rb_rational_plus(x
, y
);
93 return rb_funcall(x
, '+', 1, y
);
97 f_div(VALUE x
, VALUE y
)
99 if (FIXNUM_P(y
) && FIX2LONG(y
) == 1)
101 return rb_funcall(x
, '/', 1, y
);
105 f_gt_p(VALUE x
, VALUE y
)
107 if (RB_INTEGER_TYPE_P(x
)) {
108 if (FIXNUM_P(x
) && FIXNUM_P(y
))
109 return (SIGNED_VALUE
)x
> (SIGNED_VALUE
)y
;
110 return RTEST(rb_int_gt(x
, y
));
112 else if (RB_FLOAT_TYPE_P(x
))
113 return RTEST(rb_float_gt(x
, y
));
114 else if (RB_TYPE_P(x
, T_RATIONAL
)) {
115 int const cmp
= rb_cmpint(rb_rational_cmp(x
, y
), x
, y
);
118 return RTEST(rb_funcall(x
, '>', 1, y
));
122 f_mul(VALUE x
, VALUE y
)
124 if (RB_INTEGER_TYPE_P(x
) &&
125 LIKELY(rb_method_basic_definition_p(rb_cInteger
, idMULT
))) {
126 if (FIXNUM_ZERO_P(y
))
128 if (FIXNUM_ZERO_P(x
) && RB_INTEGER_TYPE_P(y
))
130 if (x
== ONE
) return y
;
131 if (y
== ONE
) return x
;
132 return rb_int_mul(x
, y
);
134 else if (RB_FLOAT_TYPE_P(x
) &&
135 LIKELY(rb_method_basic_definition_p(rb_cFloat
, idMULT
))) {
136 if (y
== ONE
) return x
;
137 return rb_float_mul(x
, y
);
139 else if (RB_TYPE_P(x
, T_RATIONAL
) &&
140 LIKELY(rb_method_basic_definition_p(rb_cRational
, idMULT
))) {
141 if (y
== ONE
) return x
;
142 return rb_rational_mul(x
, y
);
144 else if (LIKELY(rb_method_basic_definition_p(CLASS_OF(x
), idMULT
))) {
145 if (y
== ONE
) return x
;
147 return rb_funcall(x
, '*', 1, y
);
151 f_sub(VALUE x
, VALUE y
)
153 if (FIXNUM_ZERO_P(y
) &&
154 LIKELY(rb_method_basic_definition_p(CLASS_OF(x
), idMINUS
))) {
157 return rb_funcall(x
, '-', 1, y
);
163 if (RB_INTEGER_TYPE_P(x
)) {
164 return rb_int_abs(x
);
166 else if (RB_FLOAT_TYPE_P(x
)) {
167 return rb_float_abs(x
);
169 else if (RB_TYPE_P(x
, T_RATIONAL
)) {
170 return rb_rational_abs(x
);
172 else if (RB_TYPE_P(x
, T_COMPLEX
)) {
173 return rb_complex_abs(x
);
175 return rb_funcall(x
, id_abs
, 0);
178 static VALUE
numeric_arg(VALUE self
);
179 static VALUE
float_arg(VALUE self
);
184 if (RB_INTEGER_TYPE_P(x
)) {
185 return numeric_arg(x
);
187 else if (RB_FLOAT_TYPE_P(x
)) {
190 else if (RB_TYPE_P(x
, T_RATIONAL
)) {
191 return numeric_arg(x
);
193 else if (RB_TYPE_P(x
, T_COMPLEX
)) {
194 return rb_complex_arg(x
);
196 return rb_funcall(x
, id_arg
, 0);
202 if (RB_TYPE_P(x
, T_RATIONAL
)) {
203 return RRATIONAL(x
)->num
;
205 if (RB_FLOAT_TYPE_P(x
)) {
206 return rb_float_numerator(x
);
212 f_denominator(VALUE x
)
214 if (RB_TYPE_P(x
, T_RATIONAL
)) {
215 return RRATIONAL(x
)->den
;
217 if (RB_FLOAT_TYPE_P(x
)) {
218 return rb_float_denominator(x
);
226 if (RB_INTEGER_TYPE_P(x
)) {
227 return rb_int_uminus(x
);
229 else if (RB_FLOAT_TYPE_P(x
)) {
230 return rb_float_uminus(x
);
232 else if (RB_TYPE_P(x
, T_RATIONAL
)) {
233 return rb_rational_uminus(x
);
235 else if (RB_TYPE_P(x
, T_COMPLEX
)) {
236 return rb_complex_uminus(x
);
238 return rb_funcall(x
, id_negate
, 0);
241 static bool nucomp_real_p(VALUE self
);
246 if (RB_INTEGER_TYPE_P(x
)) {
249 else if (RB_FLOAT_TYPE_P(x
)) {
252 else if (RB_TYPE_P(x
, T_RATIONAL
)) {
255 else if (RB_TYPE_P(x
, T_COMPLEX
)) {
256 return nucomp_real_p(x
);
258 return rb_funcall(x
, id_real_p
, 0);
264 if (RB_TYPE_P(x
, T_STRING
))
265 return rb_str_to_inum(x
, 10, 0);
266 return rb_funcall(x
, id_to_i
, 0);
272 if (RB_TYPE_P(x
, T_STRING
))
273 return DBL2NUM(rb_str_to_dbl(x
, 0));
274 return rb_funcall(x
, id_to_f
, 0);
280 f_eqeq_p(VALUE x
, VALUE y
)
282 if (FIXNUM_P(x
) && FIXNUM_P(y
))
284 else if (RB_FLOAT_TYPE_P(x
) || RB_FLOAT_TYPE_P(y
))
285 return NUM2DBL(x
) == NUM2DBL(y
);
286 return (int)rb_equal(x
, y
);
293 f_quo(VALUE x
, VALUE y
)
295 if (RB_INTEGER_TYPE_P(x
))
296 return rb_numeric_quo(x
, y
);
297 if (RB_FLOAT_TYPE_P(x
))
298 return rb_float_div(x
, y
);
299 if (RB_TYPE_P(x
, T_RATIONAL
))
300 return rb_numeric_quo(x
, y
);
302 return rb_funcallv(x
, id_quo
, 1, &y
);
306 f_negative_p(VALUE x
)
308 if (RB_INTEGER_TYPE_P(x
))
309 return INT_NEGATIVE_P(x
);
310 else if (RB_FLOAT_TYPE_P(x
))
311 return RFLOAT_VALUE(x
) < 0.0;
312 else if (RB_TYPE_P(x
, T_RATIONAL
))
313 return INT_NEGATIVE_P(RRATIONAL(x
)->num
);
314 return rb_num_negative_p(x
);
317 #define f_positive_p(x) (!f_negative_p(x))
322 if (RB_FLOAT_TYPE_P(x
)) {
323 return FLOAT_ZERO_P(x
);
325 else if (RB_INTEGER_TYPE_P(x
)) {
326 return FIXNUM_ZERO_P(x
);
328 else if (RB_TYPE_P(x
, T_RATIONAL
)) {
329 const VALUE num
= RRATIONAL(x
)->num
;
330 return FIXNUM_ZERO_P(num
);
332 return (int)rb_equal(x
, ZERO
);
335 #define f_nonzero_p(x) (!f_zero_p(x))
338 always_finite_type_p(VALUE x
)
340 if (FIXNUM_P(x
)) return true;
341 if (FLONUM_P(x
)) return true; /* Infinity can't be a flonum */
342 return (RB_INTEGER_TYPE_P(x
) || RB_TYPE_P(x
, T_RATIONAL
));
348 if (always_finite_type_p(x
)) {
351 else if (RB_FLOAT_TYPE_P(x
)) {
352 return isfinite(RFLOAT_VALUE(x
));
354 return RTEST(rb_funcallv(x
, id_finite_p
, 0, 0));
358 f_infinite_p(VALUE x
)
360 if (always_finite_type_p(x
)) {
363 else if (RB_FLOAT_TYPE_P(x
)) {
364 return isinf(RFLOAT_VALUE(x
));
366 return RTEST(rb_funcallv(x
, id_infinite_p
, 0, 0));
370 f_kind_of_p(VALUE x
, VALUE c
)
372 return (int)rb_obj_is_kind_of(x
, c
);
378 return f_kind_of_p(x
, rb_cNumeric
);
381 #define k_exact_p(x) (!RB_FLOAT_TYPE_P(x))
383 #define k_exact_zero_p(x) (k_exact_p(x) && f_zero_p(x))
385 #define get_dat1(x) \
386 struct RComplex *dat = RCOMPLEX(x)
388 #define get_dat2(x,y) \
389 struct RComplex *adat = RCOMPLEX(x), *bdat = RCOMPLEX(y)
392 nucomp_s_new_internal(VALUE klass
, VALUE real
, VALUE imag
)
394 NEWOBJ_OF(obj
, struct RComplex
, klass
, T_COMPLEX
| (RGENGC_WB_PROTECTED_COMPLEX
? FL_WB_PROTECTED
: 0));
396 RCOMPLEX_SET_REAL(obj
, real
);
397 RCOMPLEX_SET_IMAG(obj
, imag
);
398 OBJ_FREEZE_RAW((VALUE
)obj
);
404 nucomp_s_alloc(VALUE klass
)
406 return nucomp_s_new_internal(klass
, ZERO
, ZERO
);
410 f_complex_new_bang1(VALUE klass
, VALUE x
)
412 assert(!RB_TYPE_P(x
, T_COMPLEX
));
413 return nucomp_s_new_internal(klass
, x
, ZERO
);
417 f_complex_new_bang2(VALUE klass
, VALUE x
, VALUE y
)
419 assert(!RB_TYPE_P(x
, T_COMPLEX
));
420 assert(!RB_TYPE_P(y
, T_COMPLEX
));
421 return nucomp_s_new_internal(klass
, x
, y
);
425 nucomp_real_check(VALUE num
)
427 if (!RB_INTEGER_TYPE_P(num
) &&
428 !RB_FLOAT_TYPE_P(num
) &&
429 !RB_TYPE_P(num
, T_RATIONAL
)) {
430 if (!k_numeric_p(num
) || !f_real_p(num
))
431 rb_raise(rb_eTypeError
, "not a real");
436 nucomp_s_canonicalize_internal(VALUE klass
, VALUE real
, VALUE imag
)
438 int complex_r
, complex_i
;
439 complex_r
= RB_TYPE_P(real
, T_COMPLEX
);
440 complex_i
= RB_TYPE_P(imag
, T_COMPLEX
);
441 if (!complex_r
&& !complex_i
) {
442 return nucomp_s_new_internal(klass
, real
, imag
);
444 else if (!complex_r
) {
447 return nucomp_s_new_internal(klass
,
448 f_sub(real
, dat
->imag
),
449 f_add(ZERO
, dat
->real
));
451 else if (!complex_i
) {
454 return nucomp_s_new_internal(klass
,
456 f_add(dat
->imag
, imag
));
459 get_dat2(real
, imag
);
461 return nucomp_s_new_internal(klass
,
462 f_sub(adat
->real
, bdat
->imag
),
463 f_add(adat
->imag
, bdat
->real
));
469 * Complex.rect(real[, imag]) -> complex
470 * Complex.rectangular(real[, imag]) -> complex
472 * Returns a complex object which denotes the given rectangular form.
474 * Complex.rectangular(1, 2) #=> (1+2i)
477 nucomp_s_new(int argc
, VALUE
*argv
, VALUE klass
)
481 switch (rb_scan_args(argc
, argv
, "11", &real
, &imag
)) {
483 nucomp_real_check(real
);
487 nucomp_real_check(real
);
488 nucomp_real_check(imag
);
492 return nucomp_s_canonicalize_internal(klass
, real
, imag
);
496 f_complex_new2(VALUE klass
, VALUE x
, VALUE y
)
498 assert(!RB_TYPE_P(x
, T_COMPLEX
));
499 return nucomp_s_canonicalize_internal(klass
, x
, y
);
502 static VALUE
nucomp_convert(VALUE klass
, VALUE a1
, VALUE a2
, int raise
);
503 static VALUE
nucomp_s_convert(int argc
, VALUE
*argv
, VALUE klass
);
507 * Complex(x[, y], exception: true) -> numeric or nil
511 * Complex(1, 2) #=> (1+2i)
512 * Complex('1+2i') #=> (1+2i)
513 * Complex(nil) #=> TypeError
514 * Complex(1, nil) #=> TypeError
516 * Complex(1, nil, exception: false) #=> nil
517 * Complex('1+2', exception: false) #=> nil
519 * Syntax of string form:
521 * string form = extra spaces , complex , extra spaces ;
522 * complex = real part | [ sign ] , imaginary part
523 * | real part , sign , imaginary part
524 * | rational , "@" , rational ;
525 * real part = rational ;
526 * imaginary part = imaginary unit | unsigned rational , imaginary unit ;
527 * rational = [ sign ] , unsigned rational ;
528 * unsigned rational = numerator | numerator , "/" , denominator ;
529 * numerator = integer part | fractional part | integer part , fractional part ;
530 * denominator = digits ;
531 * integer part = digits ;
532 * fractional part = "." , digits , [ ( "e" | "E" ) , [ sign ] , digits ] ;
533 * imaginary unit = "i" | "I" | "j" | "J" ;
535 * digits = digit , { digit | "_" , digit };
536 * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
537 * extra spaces = ? \s* ? ;
542 nucomp_f_complex(int argc
, VALUE
*argv
, VALUE klass
)
544 VALUE a1
, a2
, opts
= Qnil
;
547 if (rb_scan_args(argc
, argv
, "11:", &a1
, &a2
, &opts
) == 1) {
551 raise
= rb_opts_exception_p(opts
, raise
);
553 if (argc
> 0 && CLASS_OF(a1
) == rb_cComplex
&& a2
== Qundef
) {
556 return nucomp_convert(rb_cComplex
, a1
, a2
, raise
);
560 inline static VALUE \
561 m_##n##_bang(VALUE x)\
563 return rb_math_##n(x);\
573 return rb_math_log(1, &x
);
582 if (!RB_TYPE_P(x
, T_COMPLEX
))
583 return m_cos_bang(x
);
586 return f_complex_new2(rb_cComplex
,
587 f_mul(m_cos_bang(dat
->real
),
588 m_cosh_bang(dat
->imag
)),
589 f_mul(f_negate(m_sin_bang(dat
->real
)),
590 m_sinh_bang(dat
->imag
)));
597 if (!RB_TYPE_P(x
, T_COMPLEX
))
598 return m_sin_bang(x
);
601 return f_complex_new2(rb_cComplex
,
602 f_mul(m_sin_bang(dat
->real
),
603 m_cosh_bang(dat
->imag
)),
604 f_mul(m_cos_bang(dat
->real
),
605 m_sinh_bang(dat
->imag
)));
610 f_complex_polar(VALUE klass
, VALUE x
, VALUE y
)
612 assert(!RB_TYPE_P(x
, T_COMPLEX
));
613 assert(!RB_TYPE_P(y
, T_COMPLEX
));
614 if (f_zero_p(x
) || f_zero_p(y
)) {
615 return nucomp_s_new_internal(klass
, x
, RFLOAT_0
);
617 if (RB_FLOAT_TYPE_P(y
)) {
618 const double arg
= RFLOAT_VALUE(y
);
623 else if (arg
== M_PI_2
) {
627 else if (arg
== M_PI_2
+M_PI
) {
631 else if (RB_FLOAT_TYPE_P(x
)) {
632 const double abs
= RFLOAT_VALUE(x
);
633 const double real
= abs
* cos(arg
), imag
= abs
* sin(arg
);
638 const double ax
= sin(arg
), ay
= cos(arg
);
639 y
= f_mul(x
, DBL2NUM(ax
));
640 x
= f_mul(x
, DBL2NUM(ay
));
642 return nucomp_s_new_internal(klass
, x
, y
);
644 return nucomp_s_canonicalize_internal(klass
,
650 # define cospi(x) __cospi(x)
652 # define cospi(x) cos((x) * M_PI)
655 # define sinpi(x) __sinpi(x)
657 # define sinpi(x) sin((x) * M_PI)
659 /* returns a Complex or Float of ang*PI-rotated abs */
661 rb_dbl_complex_new_polar_pi(double abs
, double ang
)
664 const double fr
= modf(ang
, &fi
);
665 int pos
= fr
== +0.5;
667 if (pos
|| fr
== -0.5) {
668 if ((modf(fi
/ 2.0, &fi
) != fr
) ^ pos
) abs
= -abs
;
669 return rb_complex_new(RFLOAT_0
, DBL2NUM(abs
));
671 else if (fr
== 0.0) {
672 if (modf(fi
/ 2.0, &fi
) != 0.0) abs
= -abs
;
676 const double real
= abs
* cospi(ang
), imag
= abs
* sinpi(ang
);
677 return rb_complex_new(DBL2NUM(real
), DBL2NUM(imag
));
683 * Complex.polar(abs[, arg]) -> complex
685 * Returns a complex object which denotes the given polar form.
687 * Complex.polar(3, 0) #=> (3.0+0.0i)
688 * Complex.polar(3, Math::PI/2) #=> (1.836909530733566e-16+3.0i)
689 * Complex.polar(3, Math::PI) #=> (-3.0+3.673819061467132e-16i)
690 * Complex.polar(3, -Math::PI/2) #=> (1.836909530733566e-16-3.0i)
693 nucomp_s_polar(int argc
, VALUE
*argv
, VALUE klass
)
697 switch (rb_scan_args(argc
, argv
, "11", &abs
, &arg
)) {
699 nucomp_real_check(abs
);
700 return nucomp_s_new_internal(klass
, abs
, ZERO
);
702 nucomp_real_check(abs
);
703 nucomp_real_check(arg
);
706 if (RB_TYPE_P(abs
, T_COMPLEX
)) {
710 if (RB_TYPE_P(arg
, T_COMPLEX
)) {
714 return f_complex_polar(klass
, abs
, arg
);
721 * Returns the real part.
723 * Complex(7).real #=> 7
724 * Complex(9, -4).real #=> 9
727 rb_complex_real(VALUE self
)
736 * cmp.imaginary -> real
738 * Returns the imaginary part.
740 * Complex(7).imaginary #=> 0
741 * Complex(9, -4).imaginary #=> -4
744 rb_complex_imag(VALUE self
)
754 * Returns negation of the value.
756 * -Complex(1, 2) #=> (-1-2i)
759 rb_complex_uminus(VALUE self
)
762 return f_complex_new2(CLASS_OF(self
),
763 f_negate(dat
->real
), f_negate(dat
->imag
));
768 * cmp + numeric -> complex
772 * Complex(2, 3) + Complex(2, 3) #=> (4+6i)
773 * Complex(900) + Complex(1) #=> (901+0i)
774 * Complex(-2, 9) + Complex(-9, 2) #=> (-11+11i)
775 * Complex(9, 8) + 4 #=> (13+8i)
776 * Complex(20, 9) + 9.8 #=> (29.8+9i)
779 rb_complex_plus(VALUE self
, VALUE other
)
781 if (RB_TYPE_P(other
, T_COMPLEX
)) {
784 get_dat2(self
, other
);
786 real
= f_add(adat
->real
, bdat
->real
);
787 imag
= f_add(adat
->imag
, bdat
->imag
);
789 return f_complex_new2(CLASS_OF(self
), real
, imag
);
791 if (k_numeric_p(other
) && f_real_p(other
)) {
794 return f_complex_new2(CLASS_OF(self
),
795 f_add(dat
->real
, other
), dat
->imag
);
797 return rb_num_coerce_bin(self
, other
, '+');
802 * cmp - numeric -> complex
804 * Performs subtraction.
806 * Complex(2, 3) - Complex(2, 3) #=> (0+0i)
807 * Complex(900) - Complex(1) #=> (899+0i)
808 * Complex(-2, 9) - Complex(-9, 2) #=> (7+7i)
809 * Complex(9, 8) - 4 #=> (5+8i)
810 * Complex(20, 9) - 9.8 #=> (10.2+9i)
813 rb_complex_minus(VALUE self
, VALUE other
)
815 if (RB_TYPE_P(other
, T_COMPLEX
)) {
818 get_dat2(self
, other
);
820 real
= f_sub(adat
->real
, bdat
->real
);
821 imag
= f_sub(adat
->imag
, bdat
->imag
);
823 return f_complex_new2(CLASS_OF(self
), real
, imag
);
825 if (k_numeric_p(other
) && f_real_p(other
)) {
828 return f_complex_new2(CLASS_OF(self
),
829 f_sub(dat
->real
, other
), dat
->imag
);
831 return rb_num_coerce_bin(self
, other
, '-');
835 safe_mul(VALUE a
, VALUE b
, int az
, int bz
)
838 if (!az
&& bz
&& RB_FLOAT_TYPE_P(a
) && (v
= RFLOAT_VALUE(a
), !isnan(v
))) {
839 a
= signbit(v
) ? DBL2NUM(-1.0) : DBL2NUM(1.0);
841 if (!bz
&& az
&& RB_FLOAT_TYPE_P(b
) && (v
= RFLOAT_VALUE(b
), !isnan(v
))) {
842 b
= signbit(v
) ? DBL2NUM(-1.0) : DBL2NUM(1.0);
848 comp_mul(VALUE areal
, VALUE aimag
, VALUE breal
, VALUE bimag
, VALUE
*real
, VALUE
*imag
)
850 int arzero
= f_zero_p(areal
);
851 int aizero
= f_zero_p(aimag
);
852 int brzero
= f_zero_p(breal
);
853 int bizero
= f_zero_p(bimag
);
854 *real
= f_sub(safe_mul(areal
, breal
, arzero
, brzero
),
855 safe_mul(aimag
, bimag
, aizero
, bizero
));
856 *imag
= f_add(safe_mul(areal
, bimag
, arzero
, bizero
),
857 safe_mul(aimag
, breal
, aizero
, brzero
));
862 * cmp * numeric -> complex
864 * Performs multiplication.
866 * Complex(2, 3) * Complex(2, 3) #=> (-5+12i)
867 * Complex(900) * Complex(1) #=> (900+0i)
868 * Complex(-2, 9) * Complex(-9, 2) #=> (0-85i)
869 * Complex(9, 8) * 4 #=> (36+32i)
870 * Complex(20, 9) * 9.8 #=> (196.0+88.2i)
873 rb_complex_mul(VALUE self
, VALUE other
)
875 if (RB_TYPE_P(other
, T_COMPLEX
)) {
877 get_dat2(self
, other
);
879 comp_mul(adat
->real
, adat
->imag
, bdat
->real
, bdat
->imag
, &real
, &imag
);
881 return f_complex_new2(CLASS_OF(self
), real
, imag
);
883 if (k_numeric_p(other
) && f_real_p(other
)) {
886 return f_complex_new2(CLASS_OF(self
),
887 f_mul(dat
->real
, other
),
888 f_mul(dat
->imag
, other
));
890 return rb_num_coerce_bin(self
, other
, '*');
894 f_divide(VALUE self
, VALUE other
,
895 VALUE (*func
)(VALUE
, VALUE
), ID id
)
897 if (RB_TYPE_P(other
, T_COMPLEX
)) {
900 get_dat2(self
, other
);
902 flo
= (RB_FLOAT_TYPE_P(adat
->real
) || RB_FLOAT_TYPE_P(adat
->imag
) ||
903 RB_FLOAT_TYPE_P(bdat
->real
) || RB_FLOAT_TYPE_P(bdat
->imag
));
905 if (f_gt_p(f_abs(bdat
->real
), f_abs(bdat
->imag
))) {
906 r
= (*func
)(bdat
->imag
, bdat
->real
);
907 n
= f_mul(bdat
->real
, f_add(ONE
, f_mul(r
, r
)));
908 x
= (*func
)(f_add(adat
->real
, f_mul(adat
->imag
, r
)), n
);
909 y
= (*func
)(f_sub(adat
->imag
, f_mul(adat
->real
, r
)), n
);
912 r
= (*func
)(bdat
->real
, bdat
->imag
);
913 n
= f_mul(bdat
->imag
, f_add(ONE
, f_mul(r
, r
)));
914 x
= (*func
)(f_add(f_mul(adat
->real
, r
), adat
->imag
), n
);
915 y
= (*func
)(f_sub(f_mul(adat
->imag
, r
), adat
->real
), n
);
918 x
= rb_rational_canonicalize(x
);
919 y
= rb_rational_canonicalize(y
);
921 return f_complex_new2(CLASS_OF(self
), x
, y
);
923 if (k_numeric_p(other
) && f_real_p(other
)) {
926 x
= rb_rational_canonicalize((*func
)(dat
->real
, other
));
927 y
= rb_rational_canonicalize((*func
)(dat
->imag
, other
));
928 return f_complex_new2(CLASS_OF(self
), x
, y
);
930 return rb_num_coerce_bin(self
, other
, id
);
933 #define rb_raise_zerodiv() rb_raise(rb_eZeroDivError, "divided by 0")
937 * cmp / numeric -> complex
938 * cmp.quo(numeric) -> complex
942 * Complex(2, 3) / Complex(2, 3) #=> ((1/1)+(0/1)*i)
943 * Complex(900) / Complex(1) #=> ((900/1)+(0/1)*i)
944 * Complex(-2, 9) / Complex(-9, 2) #=> ((36/85)-(77/85)*i)
945 * Complex(9, 8) / 4 #=> ((9/4)+(2/1)*i)
946 * Complex(20, 9) / 9.8 #=> (2.0408163265306123+0.9183673469387754i)
949 rb_complex_div(VALUE self
, VALUE other
)
951 return f_divide(self
, other
, f_quo
, id_quo
);
954 #define nucomp_quo rb_complex_div
958 * cmp.fdiv(numeric) -> complex
960 * Performs division as each part is a float, never returns a float.
962 * Complex(11, 22).fdiv(3) #=> (3.6666666666666665+7.333333333333333i)
965 nucomp_fdiv(VALUE self
, VALUE other
)
967 return f_divide(self
, other
, f_fdiv
, id_fdiv
);
971 f_reciprocal(VALUE x
)
973 return f_quo(ONE
, x
);
978 * cmp ** numeric -> complex
980 * Performs exponentiation.
982 * Complex('i') ** 2 #=> (-1+0i)
983 * Complex(-8) ** Rational(1, 3) #=> (1.0000000000000002+1.7320508075688772i)
986 rb_complex_pow(VALUE self
, VALUE other
)
988 if (k_numeric_p(other
) && k_exact_zero_p(other
))
989 return f_complex_new_bang1(CLASS_OF(self
), ONE
);
991 if (RB_TYPE_P(other
, T_RATIONAL
) && RRATIONAL(other
)->den
== LONG2FIX(1))
992 other
= RRATIONAL(other
)->num
; /* c14n */
994 if (RB_TYPE_P(other
, T_COMPLEX
)) {
997 if (k_exact_zero_p(dat
->imag
))
998 other
= dat
->real
; /* c14n */
1001 if (RB_TYPE_P(other
, T_COMPLEX
)) {
1002 VALUE r
, theta
, nr
, ntheta
;
1007 theta
= f_arg(self
);
1009 nr
= m_exp_bang(f_sub(f_mul(dat
->real
, m_log_bang(r
)),
1010 f_mul(dat
->imag
, theta
)));
1011 ntheta
= f_add(f_mul(theta
, dat
->real
),
1012 f_mul(dat
->imag
, m_log_bang(r
)));
1013 return f_complex_polar(CLASS_OF(self
), nr
, ntheta
);
1015 if (FIXNUM_P(other
)) {
1016 long n
= FIX2LONG(other
);
1018 return nucomp_s_new_internal(CLASS_OF(self
), ONE
, ZERO
);
1021 self
= f_reciprocal(self
);
1022 other
= rb_int_uminus(other
);
1027 VALUE xr
= dat
->real
, xi
= dat
->imag
, zr
= xr
, zi
= xi
;
1030 zr
= rb_num_pow(zr
, other
);
1032 else if (f_zero_p(xr
)) {
1033 zi
= rb_num_pow(zi
, other
);
1034 if (n
& 2) zi
= f_negate(zi
);
1045 for (; q
= n
/ 2, r
= n
% 2, r
== 0; n
= q
) {
1046 VALUE tmp
= f_sub(f_mul(xr
, xr
), f_mul(xi
, xi
));
1047 xi
= f_mul(f_mul(TWO
, xr
), xi
);
1050 comp_mul(zr
, zi
, xr
, xi
, &zr
, &zi
);
1053 return nucomp_s_new_internal(CLASS_OF(self
), zr
, zi
);
1056 if (k_numeric_p(other
) && f_real_p(other
)) {
1059 if (RB_BIGNUM_TYPE_P(other
))
1060 rb_warn("in a**b, b may be too big");
1063 theta
= f_arg(self
);
1065 return f_complex_polar(CLASS_OF(self
), f_expt(r
, other
),
1066 f_mul(theta
, other
));
1068 return rb_num_coerce_bin(self
, other
, id_expt
);
1073 * cmp == object -> true or false
1075 * Returns true if cmp equals object numerically.
1077 * Complex(2, 3) == Complex(2, 3) #=> true
1078 * Complex(5) == 5 #=> true
1079 * Complex(0) == 0.0 #=> true
1080 * Complex('1/3') == 0.33 #=> false
1081 * Complex('1/2') == '1/2' #=> false
1084 nucomp_eqeq_p(VALUE self
, VALUE other
)
1086 if (RB_TYPE_P(other
, T_COMPLEX
)) {
1087 get_dat2(self
, other
);
1089 return RBOOL(f_eqeq_p(adat
->real
, bdat
->real
) &&
1090 f_eqeq_p(adat
->imag
, bdat
->imag
));
1092 if (k_numeric_p(other
) && f_real_p(other
)) {
1095 return RBOOL(f_eqeq_p(dat
->real
, other
) && f_zero_p(dat
->imag
));
1097 return RBOOL(f_eqeq_p(other
, self
));
1101 nucomp_real_p(VALUE self
)
1104 return(f_zero_p(dat
->imag
) ? true : false);
1109 * cmp <=> object -> 0, 1, -1, or nil
1111 * If +cmp+'s imaginary part is zero, and +object+ is also a
1112 * real number (or a Complex number where the imaginary part is zero),
1113 * compare the real part of +cmp+ to object. Otherwise, return nil.
1115 * Complex(2, 3) <=> Complex(2, 3) #=> nil
1116 * Complex(2, 3) <=> 1 #=> nil
1117 * Complex(2) <=> 1 #=> 1
1118 * Complex(2) <=> 2 #=> 0
1119 * Complex(2) <=> 3 #=> -1
1122 nucomp_cmp(VALUE self
, VALUE other
)
1124 if (nucomp_real_p(self
) && k_numeric_p(other
)) {
1125 if (RB_TYPE_P(other
, T_COMPLEX
) && nucomp_real_p(other
)) {
1126 get_dat2(self
, other
);
1127 return rb_funcall(adat
->real
, idCmp
, 1, bdat
->real
);
1129 else if (f_real_p(other
)) {
1131 return rb_funcall(dat
->real
, idCmp
, 1, other
);
1139 nucomp_coerce(VALUE self
, VALUE other
)
1141 if (RB_TYPE_P(other
, T_COMPLEX
))
1142 return rb_assoc_new(other
, self
);
1143 if (k_numeric_p(other
) && f_real_p(other
))
1144 return rb_assoc_new(f_complex_new_bang1(CLASS_OF(self
), other
), self
);
1146 rb_raise(rb_eTypeError
, "%"PRIsVALUE
" can't be coerced into %"PRIsVALUE
,
1147 rb_obj_class(other
), rb_obj_class(self
));
1154 * cmp.magnitude -> real
1156 * Returns the absolute part of its polar form.
1158 * Complex(-1).abs #=> 1
1159 * Complex(3.0, -4.0).abs #=> 5.0
1162 rb_complex_abs(VALUE self
)
1166 if (f_zero_p(dat
->real
)) {
1167 VALUE a
= f_abs(dat
->imag
);
1168 if (RB_FLOAT_TYPE_P(dat
->real
) && !RB_FLOAT_TYPE_P(dat
->imag
))
1172 if (f_zero_p(dat
->imag
)) {
1173 VALUE a
= f_abs(dat
->real
);
1174 if (!RB_FLOAT_TYPE_P(dat
->real
) && RB_FLOAT_TYPE_P(dat
->imag
))
1178 return rb_math_hypot(dat
->real
, dat
->imag
);
1185 * Returns square of the absolute value.
1187 * Complex(-1).abs2 #=> 1
1188 * Complex(3.0, -4.0).abs2 #=> 25.0
1191 nucomp_abs2(VALUE self
)
1194 return f_add(f_mul(dat
->real
, dat
->real
),
1195 f_mul(dat
->imag
, dat
->imag
));
1201 * cmp.angle -> float
1202 * cmp.phase -> float
1204 * Returns the angle part of its polar form.
1206 * Complex.polar(3, Math::PI/2).arg #=> 1.5707963267948966
1209 rb_complex_arg(VALUE self
)
1212 return rb_math_atan2(dat
->imag
, dat
->real
);
1218 * cmp.rectangular -> array
1220 * Returns an array; [cmp.real, cmp.imag].
1222 * Complex(1, 2).rectangular #=> [1, 2]
1225 nucomp_rect(VALUE self
)
1228 return rb_assoc_new(dat
->real
, dat
->imag
);
1233 * cmp.polar -> array
1235 * Returns an array; [cmp.abs, cmp.arg].
1237 * Complex(1, 2).polar #=> [2.23606797749979, 1.1071487177940904]
1240 nucomp_polar(VALUE self
)
1242 return rb_assoc_new(f_abs(self
), f_arg(self
));
1247 * cmp.conj -> complex
1248 * cmp.conjugate -> complex
1250 * Returns the complex conjugate.
1252 * Complex(1, 2).conjugate #=> (1-2i)
1255 rb_complex_conjugate(VALUE self
)
1258 return f_complex_new2(CLASS_OF(self
), dat
->real
, f_negate(dat
->imag
));
1263 * Complex(1).real? -> false
1264 * Complex(1, 2).real? -> false
1266 * Returns false, even if the complex number has no imaginary part.
1269 nucomp_real_p_m(VALUE self
)
1276 * cmp.denominator -> integer
1278 * Returns the denominator (lcm of both denominator - real and imag).
1283 nucomp_denominator(VALUE self
)
1286 return rb_lcm(f_denominator(dat
->real
), f_denominator(dat
->imag
));
1291 * cmp.numerator -> numeric
1293 * Returns the numerator.
1295 * 1 2 3+4i <- numerator
1297 * 2 3 6 <- denominator
1299 * c = Complex('1/2+2/3i') #=> ((1/2)+(2/3)*i)
1300 * n = c.numerator #=> (3+4i)
1301 * d = c.denominator #=> 6
1302 * n / d #=> ((1/2)+(2/3)*i)
1303 * Complex(Rational(n.real, d), Rational(n.imag, d))
1304 * #=> ((1/2)+(2/3)*i)
1308 nucomp_numerator(VALUE self
)
1314 cd
= nucomp_denominator(self
);
1315 return f_complex_new2(CLASS_OF(self
),
1316 f_mul(f_numerator(dat
->real
),
1317 f_div(cd
, f_denominator(dat
->real
))),
1318 f_mul(f_numerator(dat
->imag
),
1319 f_div(cd
, f_denominator(dat
->imag
))));
1324 rb_complex_hash(VALUE self
)
1330 n
= rb_hash(dat
->real
);
1332 n
= rb_hash(dat
->imag
);
1334 v
= rb_memhash(h
, sizeof(h
));
1339 nucomp_hash(VALUE self
)
1341 return ST2FIX(rb_complex_hash(self
));
1346 nucomp_eql_p(VALUE self
, VALUE other
)
1348 if (RB_TYPE_P(other
, T_COMPLEX
)) {
1349 get_dat2(self
, other
);
1351 return RBOOL((CLASS_OF(adat
->real
) == CLASS_OF(bdat
->real
)) &&
1352 (CLASS_OF(adat
->imag
) == CLASS_OF(bdat
->imag
)) &&
1353 f_eqeq_p(self
, other
));
1362 if (RB_FLOAT_TYPE_P(x
)) {
1363 double f
= RFLOAT_VALUE(x
);
1364 return !isnan(f
) && signbit(f
);
1366 return f_negative_p(x
);
1370 f_tpositive_p(VALUE x
)
1372 return !f_signbit(x
);
1376 f_format(VALUE self
, VALUE (*func
)(VALUE
))
1383 impos
= f_tpositive_p(dat
->imag
);
1385 s
= (*func
)(dat
->real
);
1386 rb_str_cat2(s
, !impos
? "-" : "+");
1388 rb_str_concat(s
, (*func
)(f_abs(dat
->imag
)));
1389 if (!rb_isdigit(RSTRING_PTR(s
)[RSTRING_LEN(s
) - 1]))
1390 rb_str_cat2(s
, "*");
1391 rb_str_cat2(s
, "i");
1398 * cmp.to_s -> string
1400 * Returns the value as a string.
1402 * Complex(2).to_s #=> "2+0i"
1403 * Complex('-8/6').to_s #=> "-4/3+0i"
1404 * Complex('1/2i').to_s #=> "0+1/2i"
1405 * Complex(0, Float::INFINITY).to_s #=> "0+Infinity*i"
1406 * Complex(Float::NAN, Float::NAN).to_s #=> "NaN+NaN*i"
1409 nucomp_to_s(VALUE self
)
1411 return f_format(self
, rb_String
);
1416 * cmp.inspect -> string
1418 * Returns the value as a string for inspection.
1420 * Complex(2).inspect #=> "(2+0i)"
1421 * Complex('-8/6').inspect #=> "((-4/3)+0i)"
1422 * Complex('1/2i').inspect #=> "(0+(1/2)*i)"
1423 * Complex(0, Float::INFINITY).inspect #=> "(0+Infinity*i)"
1424 * Complex(Float::NAN, Float::NAN).inspect #=> "(NaN+NaN*i)"
1427 nucomp_inspect(VALUE self
)
1431 s
= rb_usascii_str_new2("(");
1432 rb_str_concat(s
, f_format(self
, rb_inspect
));
1433 rb_str_cat2(s
, ")");
1438 #define FINITE_TYPE_P(v) (RB_INTEGER_TYPE_P(v) || RB_TYPE_P(v, T_RATIONAL))
1442 * cmp.finite? -> true or false
1444 * Returns +true+ if +cmp+'s real and imaginary parts are both finite numbers,
1445 * otherwise returns +false+.
1448 rb_complex_finite_p(VALUE self
)
1452 return RBOOL(f_finite_p(dat
->real
) && f_finite_p(dat
->imag
));
1457 * cmp.infinite? -> nil or 1
1459 * Returns +1+ if +cmp+'s real or imaginary part is an infinite number,
1460 * otherwise returns +nil+.
1464 * (1+1i).infinite? #=> nil
1465 * (Float::INFINITY + 1i).infinite? #=> 1
1468 rb_complex_infinite_p(VALUE self
)
1472 if (!f_infinite_p(dat
->real
) && !f_infinite_p(dat
->imag
)) {
1480 nucomp_dumper(VALUE self
)
1487 nucomp_loader(VALUE self
, VALUE a
)
1491 RCOMPLEX_SET_REAL(dat
, rb_ivar_get(a
, id_i_real
));
1492 RCOMPLEX_SET_IMAG(dat
, rb_ivar_get(a
, id_i_imag
));
1493 OBJ_FREEZE_RAW(self
);
1500 nucomp_marshal_dump(VALUE self
)
1505 a
= rb_assoc_new(dat
->real
, dat
->imag
);
1506 rb_copy_generic_ivar(a
, self
);
1512 nucomp_marshal_load(VALUE self
, VALUE a
)
1514 Check_Type(a
, T_ARRAY
);
1515 if (RARRAY_LEN(a
) != 2)
1516 rb_raise(rb_eArgError
, "marshaled complex must have an array whose length is 2 but %ld", RARRAY_LEN(a
));
1517 rb_ivar_set(self
, id_i_real
, RARRAY_AREF(a
, 0));
1518 rb_ivar_set(self
, id_i_imag
, RARRAY_AREF(a
, 1));
1523 rb_complex_raw(VALUE x
, VALUE y
)
1525 return nucomp_s_new_internal(rb_cComplex
, x
, y
);
1529 rb_complex_new(VALUE x
, VALUE y
)
1531 return nucomp_s_canonicalize_internal(rb_cComplex
, x
, y
);
1535 rb_complex_new_polar(VALUE x
, VALUE y
)
1537 return f_complex_polar(rb_cComplex
, x
, y
);
1541 rb_complex_polar(VALUE x
, VALUE y
)
1543 return rb_complex_new_polar(x
, y
);
1547 rb_Complex(VALUE x
, VALUE y
)
1552 return nucomp_s_convert(2, a
, rb_cComplex
);
1556 rb_dbl_complex_new(double real
, double imag
)
1558 return rb_complex_raw(DBL2NUM(real
), DBL2NUM(imag
));
1563 * cmp.to_i -> integer
1565 * Returns the value as an integer if possible (the imaginary part
1566 * should be exactly zero).
1568 * Complex(1, 0).to_i #=> 1
1569 * Complex(1, 0.0).to_i # RangeError
1570 * Complex(1, 2).to_i # RangeError
1573 nucomp_to_i(VALUE self
)
1577 if (!k_exact_zero_p(dat
->imag
)) {
1578 rb_raise(rb_eRangeError
, "can't convert %"PRIsVALUE
" into Integer",
1581 return f_to_i(dat
->real
);
1588 * Returns the value as a float if possible (the imaginary part should
1591 * Complex(1, 0).to_f #=> 1.0
1592 * Complex(1, 0.0).to_f # RangeError
1593 * Complex(1, 2).to_f # RangeError
1596 nucomp_to_f(VALUE self
)
1600 if (!k_exact_zero_p(dat
->imag
)) {
1601 rb_raise(rb_eRangeError
, "can't convert %"PRIsVALUE
" into Float",
1604 return f_to_f(dat
->real
);
1609 * cmp.to_r -> rational
1611 * Returns the value as a rational if possible (the imaginary part
1612 * should be exactly zero).
1614 * Complex(1, 0).to_r #=> (1/1)
1615 * Complex(1, 0.0).to_r # RangeError
1616 * Complex(1, 2).to_r # RangeError
1621 nucomp_to_r(VALUE self
)
1625 if (!k_exact_zero_p(dat
->imag
)) {
1626 rb_raise(rb_eRangeError
, "can't convert %"PRIsVALUE
" into Rational",
1629 return f_to_r(dat
->real
);
1634 * cmp.rationalize([eps]) -> rational
1636 * Returns the value as a rational if possible (the imaginary part
1637 * should be exactly zero).
1639 * Complex(1.0/3, 0).rationalize #=> (1/3)
1640 * Complex(1, 0.0).rationalize # RangeError
1641 * Complex(1, 2).rationalize # RangeError
1646 nucomp_rationalize(int argc
, VALUE
*argv
, VALUE self
)
1650 rb_check_arity(argc
, 0, 1);
1652 if (!k_exact_zero_p(dat
->imag
)) {
1653 rb_raise(rb_eRangeError
, "can't convert %"PRIsVALUE
" into Rational",
1656 return rb_funcallv(dat
->real
, id_rationalize
, argc
, argv
);
1661 * complex.to_c -> self
1665 * Complex(2).to_c #=> (2+0i)
1666 * Complex(-8, 6).to_c #=> (-8+6i)
1669 nucomp_to_c(VALUE self
)
1676 * nil.to_c -> (0+0i)
1678 * Returns zero as a complex.
1681 nilclass_to_c(VALUE self
)
1683 return rb_complex_new1(INT2FIX(0));
1688 * num.to_c -> complex
1690 * Returns the value as a complex.
1693 numeric_to_c(VALUE self
)
1695 return rb_complex_new1(self
);
1701 return (c
== '-' || c
== '+');
1705 read_sign(const char **s
,
1721 return isdigit((unsigned char)c
);
1725 read_digits(const char **s
, int strict
,
1730 if (!isdecimal(**s
))
1733 while (isdecimal(**s
) || **s
== '_') {
1751 } while (**s
== '_');
1758 return (c
== 'e' || c
== 'E');
1762 read_num(const char **s
, int strict
,
1766 if (!read_digits(s
, strict
, b
))
1774 if (!read_digits(s
, strict
, b
)) {
1780 if (islettere(**s
)) {
1785 if (!read_digits(s
, strict
, b
)) {
1794 read_den(const char **s
, int strict
,
1797 if (!read_digits(s
, strict
, b
))
1803 read_rat_nos(const char **s
, int strict
,
1806 if (!read_num(s
, strict
, b
))
1812 if (!read_den(s
, strict
, b
)) {
1821 read_rat(const char **s
, int strict
,
1825 if (!read_rat_nos(s
, strict
, b
))
1833 return (c
== 'i' || c
== 'I' ||
1834 c
== 'j' || c
== 'J');
1841 return rb_cstr_to_rat(s
, 0);
1842 if (strpbrk(s
, ".eE"))
1843 return DBL2NUM(rb_cstr_to_dbl(s
, 0));
1844 return rb_cstr_to_inum(s
, 10, 0);
1848 read_comp(const char **s
, int strict
,
1849 VALUE
*ret
, char **b
)
1857 sign
= read_sign(s
, b
);
1859 if (isimagunit(**s
)) {
1861 num
= INT2FIX((sign
== '-') ? -1 : + 1);
1862 *ret
= rb_complex_new2(ZERO
, num
);
1863 return 1; /* e.g. "i" */
1866 if (!read_rat_nos(s
, strict
, b
)) {
1869 *ret
= rb_complex_new2(num
, ZERO
);
1870 return 0; /* e.g. "-" */
1875 if (isimagunit(**s
)) {
1877 *ret
= rb_complex_new2(ZERO
, num
);
1878 return 1; /* e.g. "3i" */
1886 st
= read_rat(s
, strict
, b
);
1888 if (strlen(bb
) < 1 ||
1889 !isdecimal(*(bb
+ strlen(bb
) - 1))) {
1890 *ret
= rb_complex_new2(num
, ZERO
);
1891 return 0; /* e.g. "1@-" */
1894 *ret
= rb_complex_new_polar(num
, num2
);
1896 return 0; /* e.g. "1@2." */
1898 return 1; /* e.g. "1@2" */
1903 sign
= read_sign(s
, b
);
1904 if (isimagunit(**s
))
1905 num2
= INT2FIX((sign
== '-') ? -1 : + 1);
1907 if (!read_rat_nos(s
, strict
, b
)) {
1908 *ret
= rb_complex_new2(num
, ZERO
);
1909 return 0; /* e.g. "1+xi" */
1914 if (!isimagunit(**s
)) {
1915 *ret
= rb_complex_new2(num
, ZERO
);
1916 return 0; /* e.g. "1+3x" */
1919 *ret
= rb_complex_new2(num
, num2
);
1920 return 1; /* e.g. "1+2i" */
1924 *ret
= rb_complex_new2(num
, ZERO
);
1925 return 1; /* e.g. "3" */
1930 skip_ws(const char **s
)
1932 while (isspace((unsigned char)**s
))
1937 parse_comp(const char *s
, int strict
, VALUE
*num
)
1943 buf
= ALLOCV_N(char, tmp
, strlen(s
) + 1);
1947 if (!read_comp(&s
, strict
, num
, &b
)) {
1963 string_to_c_strict(VALUE self
, int raise
)
1968 rb_must_asciicompat(self
);
1970 s
= RSTRING_PTR(self
);
1972 if (!s
|| memchr(s
, '\0', RSTRING_LEN(self
))) {
1973 if (!raise
) return Qnil
;
1974 rb_raise(rb_eArgError
, "string contains null byte");
1977 if (s
&& s
[RSTRING_LEN(self
)]) {
1978 rb_str_modify(self
);
1979 s
= RSTRING_PTR(self
);
1980 s
[RSTRING_LEN(self
)] = '\0';
1986 if (!parse_comp(s
, 1, &num
)) {
1987 if (!raise
) return Qnil
;
1988 rb_raise(rb_eArgError
, "invalid value for convert(): %+"PRIsVALUE
,
1997 * str.to_c -> complex
1999 * Returns a complex which denotes the string form. The parser
2000 * ignores leading whitespaces and trailing garbage. Any digit
2001 * sequences can be separated by an underscore. Returns zero for null
2002 * or garbage string.
2004 * '9'.to_c #=> (9+0i)
2005 * '2.5'.to_c #=> (2.5+0i)
2006 * '2.5/1'.to_c #=> ((5/2)+0i)
2007 * '-3/2'.to_c #=> ((-3/2)+0i)
2008 * '-i'.to_c #=> (0-1i)
2009 * '45i'.to_c #=> (0+45i)
2010 * '3-4i'.to_c #=> (3-4i)
2011 * '-4e2-4e-2i'.to_c #=> (-400.0-0.04i)
2012 * '-0.0-0.0i'.to_c #=> (-0.0-0.0i)
2013 * '1/2+3/4i'.to_c #=> ((1/2)+(3/4)*i)
2014 * 'ruby'.to_c #=> (0+0i)
2016 * See Kernel.Complex.
2019 string_to_c(VALUE self
)
2024 rb_must_asciicompat(self
);
2026 s
= RSTRING_PTR(self
);
2028 if (s
&& s
[RSTRING_LEN(self
)]) {
2029 rb_str_modify(self
);
2030 s
= RSTRING_PTR(self
);
2031 s
[RSTRING_LEN(self
)] = '\0';
2037 (void)parse_comp(s
, 0, &num
);
2043 to_complex(VALUE val
)
2045 return rb_convert_type(val
, T_COMPLEX
, "Complex", "to_c");
2049 nucomp_convert(VALUE klass
, VALUE a1
, VALUE a2
, int raise
)
2051 if (NIL_P(a1
) || NIL_P(a2
)) {
2052 if (!raise
) return Qnil
;
2053 rb_raise(rb_eTypeError
, "can't convert nil into Complex");
2056 if (RB_TYPE_P(a1
, T_STRING
)) {
2057 a1
= string_to_c_strict(a1
, raise
);
2058 if (NIL_P(a1
)) return Qnil
;
2061 if (RB_TYPE_P(a2
, T_STRING
)) {
2062 a2
= string_to_c_strict(a2
, raise
);
2063 if (NIL_P(a2
)) return Qnil
;
2066 if (RB_TYPE_P(a1
, T_COMPLEX
)) {
2070 if (k_exact_zero_p(dat
->imag
))
2075 if (RB_TYPE_P(a2
, T_COMPLEX
)) {
2079 if (k_exact_zero_p(dat
->imag
))
2084 if (RB_TYPE_P(a1
, T_COMPLEX
)) {
2085 if (a2
== Qundef
|| (k_exact_zero_p(a2
)))
2090 if (k_numeric_p(a1
) && !f_real_p(a1
))
2092 /* should raise exception for consistency */
2093 if (!k_numeric_p(a1
)) {
2095 return rb_protect(to_complex
, a1
, NULL
);
2096 return to_complex(a1
);
2100 if ((k_numeric_p(a1
) && k_numeric_p(a2
)) &&
2101 (!f_real_p(a1
) || !f_real_p(a2
)))
2104 f_complex_new_bang2(rb_cComplex
, ZERO
, ONE
)));
2116 if (!raise
&& !RB_INTEGER_TYPE_P(a2
) && !RB_FLOAT_TYPE_P(a2
) && !RB_TYPE_P(a2
, T_RATIONAL
))
2121 return nucomp_s_new(argc
, argv2
, klass
);
2126 nucomp_s_convert(int argc
, VALUE
*argv
, VALUE klass
)
2130 if (rb_scan_args(argc
, argv
, "11", &a1
, &a2
) == 1) {
2134 return nucomp_convert(klass
, a1
, a2
, TRUE
);
2144 numeric_real(VALUE self
)
2152 * num.imaginary -> 0
2157 numeric_imag(VALUE self
)
2166 * Returns square of self.
2169 numeric_abs2(VALUE self
)
2171 return f_mul(self
, self
);
2176 * num.arg -> 0 or float
2177 * num.angle -> 0 or float
2178 * num.phase -> 0 or float
2180 * Returns 0 if the value is positive, pi otherwise.
2183 numeric_arg(VALUE self
)
2185 if (f_positive_p(self
))
2187 return DBL2NUM(M_PI
);
2193 * num.rectangular -> array
2195 * Returns an array; [num, 0].
2198 numeric_rect(VALUE self
)
2200 return rb_assoc_new(self
, INT2FIX(0));
2205 * num.polar -> array
2207 * Returns an array; [num.abs, num.arg].
2210 numeric_polar(VALUE self
)
2214 if (RB_INTEGER_TYPE_P(self
)) {
2215 abs
= rb_int_abs(self
);
2216 arg
= numeric_arg(self
);
2218 else if (RB_FLOAT_TYPE_P(self
)) {
2219 abs
= rb_float_abs(self
);
2220 arg
= float_arg(self
);
2222 else if (RB_TYPE_P(self
, T_RATIONAL
)) {
2223 abs
= rb_rational_abs(self
);
2224 arg
= numeric_arg(self
);
2230 return rb_assoc_new(abs
, arg
);
2236 * num.conjugate -> self
2241 numeric_conj(VALUE self
)
2248 * flo.arg -> 0 or float
2249 * flo.angle -> 0 or float
2250 * flo.phase -> 0 or float
2252 * Returns 0 if the value is positive, pi otherwise.
2255 float_arg(VALUE self
)
2257 if (isnan(RFLOAT_VALUE(self
)))
2259 if (f_tpositive_p(self
))
2261 return rb_const_get(rb_mMath
, id_PI
);
2265 * A complex number can be represented as a paired real number with
2266 * imaginary unit; a+bi. Where a is real part, b is imaginary part
2267 * and i is imaginary unit. Real a equals complex a+0i
2270 * You can create a \Complex object explicitly with:
2272 * - A {complex literal}[doc/syntax/literals_rdoc.html#label-Complex+Literals].
2274 * You can convert certain objects to \Complex objects with:
2276 * - \Method {Complex}[Kernel.html#method-i-Complex].
2278 * Complex object can be created as literal, and also by using
2279 * Kernel#Complex, Complex::rect, Complex::polar or to_c method.
2282 * Complex(1) #=> (1+0i)
2283 * Complex(2, 3) #=> (2+3i)
2284 * Complex.polar(2, 3) #=> (-1.9799849932008908+0.2822400161197344i)
2287 * You can also create complex object from floating-point numbers or
2290 * Complex(0.3) #=> (0.3+0i)
2291 * Complex('0.3-0.5i') #=> (0.3-0.5i)
2292 * Complex('2/3+3/4i') #=> ((2/3)+(3/4)*i)
2293 * Complex('1@2') #=> (-0.4161468365471424+0.9092974268256817i)
2295 * 0.3.to_c #=> (0.3+0i)
2296 * '0.3-0.5i'.to_c #=> (0.3-0.5i)
2297 * '2/3+3/4i'.to_c #=> ((2/3)+(3/4)*i)
2298 * '1@2'.to_c #=> (-0.4161468365471424+0.9092974268256817i)
2300 * A complex object is either an exact or an inexact number.
2302 * Complex(1, 1) / 2 #=> ((1/2)+(1/2)*i)
2303 * Complex(1, 1) / 2.0 #=> (0.5+0.5i)
2309 id_abs
= rb_intern_const("abs");
2310 id_arg
= rb_intern_const("arg");
2311 id_denominator
= rb_intern_const("denominator");
2312 id_numerator
= rb_intern_const("numerator");
2313 id_real_p
= rb_intern_const("real?");
2314 id_i_real
= rb_intern_const("@real");
2315 id_i_imag
= rb_intern_const("@image"); /* @image, not @imag */
2316 id_finite_p
= rb_intern_const("finite?");
2317 id_infinite_p
= rb_intern_const("infinite?");
2318 id_rationalize
= rb_intern_const("rationalize");
2319 id_PI
= rb_intern_const("PI");
2321 rb_cComplex
= rb_define_class("Complex", rb_cNumeric
);
2323 rb_define_alloc_func(rb_cComplex
, nucomp_s_alloc
);
2324 rb_undef_method(CLASS_OF(rb_cComplex
), "allocate");
2326 rb_undef_method(CLASS_OF(rb_cComplex
), "new");
2328 rb_define_singleton_method(rb_cComplex
, "rectangular", nucomp_s_new
, -1);
2329 rb_define_singleton_method(rb_cComplex
, "rect", nucomp_s_new
, -1);
2330 rb_define_singleton_method(rb_cComplex
, "polar", nucomp_s_polar
, -1);
2332 rb_define_global_function("Complex", nucomp_f_complex
, -1);
2334 rb_undef_methods_from(rb_cComplex
, RCLASS_ORIGIN(rb_mComparable
));
2335 rb_undef_method(rb_cComplex
, "%");
2336 rb_undef_method(rb_cComplex
, "div");
2337 rb_undef_method(rb_cComplex
, "divmod");
2338 rb_undef_method(rb_cComplex
, "floor");
2339 rb_undef_method(rb_cComplex
, "ceil");
2340 rb_undef_method(rb_cComplex
, "modulo");
2341 rb_undef_method(rb_cComplex
, "remainder");
2342 rb_undef_method(rb_cComplex
, "round");
2343 rb_undef_method(rb_cComplex
, "step");
2344 rb_undef_method(rb_cComplex
, "truncate");
2345 rb_undef_method(rb_cComplex
, "i");
2347 rb_define_method(rb_cComplex
, "real", rb_complex_real
, 0);
2348 rb_define_method(rb_cComplex
, "imaginary", rb_complex_imag
, 0);
2349 rb_define_method(rb_cComplex
, "imag", rb_complex_imag
, 0);
2351 rb_define_method(rb_cComplex
, "-@", rb_complex_uminus
, 0);
2352 rb_define_method(rb_cComplex
, "+", rb_complex_plus
, 1);
2353 rb_define_method(rb_cComplex
, "-", rb_complex_minus
, 1);
2354 rb_define_method(rb_cComplex
, "*", rb_complex_mul
, 1);
2355 rb_define_method(rb_cComplex
, "/", rb_complex_div
, 1);
2356 rb_define_method(rb_cComplex
, "quo", nucomp_quo
, 1);
2357 rb_define_method(rb_cComplex
, "fdiv", nucomp_fdiv
, 1);
2358 rb_define_method(rb_cComplex
, "**", rb_complex_pow
, 1);
2360 rb_define_method(rb_cComplex
, "==", nucomp_eqeq_p
, 1);
2361 rb_define_method(rb_cComplex
, "<=>", nucomp_cmp
, 1);
2362 rb_define_method(rb_cComplex
, "coerce", nucomp_coerce
, 1);
2364 rb_define_method(rb_cComplex
, "abs", rb_complex_abs
, 0);
2365 rb_define_method(rb_cComplex
, "magnitude", rb_complex_abs
, 0);
2366 rb_define_method(rb_cComplex
, "abs2", nucomp_abs2
, 0);
2367 rb_define_method(rb_cComplex
, "arg", rb_complex_arg
, 0);
2368 rb_define_method(rb_cComplex
, "angle", rb_complex_arg
, 0);
2369 rb_define_method(rb_cComplex
, "phase", rb_complex_arg
, 0);
2370 rb_define_method(rb_cComplex
, "rectangular", nucomp_rect
, 0);
2371 rb_define_method(rb_cComplex
, "rect", nucomp_rect
, 0);
2372 rb_define_method(rb_cComplex
, "polar", nucomp_polar
, 0);
2373 rb_define_method(rb_cComplex
, "conjugate", rb_complex_conjugate
, 0);
2374 rb_define_method(rb_cComplex
, "conj", rb_complex_conjugate
, 0);
2376 rb_define_method(rb_cComplex
, "real?", nucomp_real_p_m
, 0);
2378 rb_define_method(rb_cComplex
, "numerator", nucomp_numerator
, 0);
2379 rb_define_method(rb_cComplex
, "denominator", nucomp_denominator
, 0);
2381 rb_define_method(rb_cComplex
, "hash", nucomp_hash
, 0);
2382 rb_define_method(rb_cComplex
, "eql?", nucomp_eql_p
, 1);
2384 rb_define_method(rb_cComplex
, "to_s", nucomp_to_s
, 0);
2385 rb_define_method(rb_cComplex
, "inspect", nucomp_inspect
, 0);
2387 rb_undef_method(rb_cComplex
, "positive?");
2388 rb_undef_method(rb_cComplex
, "negative?");
2390 rb_define_method(rb_cComplex
, "finite?", rb_complex_finite_p
, 0);
2391 rb_define_method(rb_cComplex
, "infinite?", rb_complex_infinite_p
, 0);
2393 rb_define_private_method(rb_cComplex
, "marshal_dump", nucomp_marshal_dump
, 0);
2395 compat
= rb_define_class_under(rb_cComplex
, "compatible", rb_cObject
);
2396 rb_define_private_method(compat
, "marshal_load", nucomp_marshal_load
, 1);
2397 rb_marshal_define_compat(rb_cComplex
, compat
, nucomp_dumper
, nucomp_loader
);
2399 rb_define_method(rb_cComplex
, "to_i", nucomp_to_i
, 0);
2400 rb_define_method(rb_cComplex
, "to_f", nucomp_to_f
, 0);
2401 rb_define_method(rb_cComplex
, "to_r", nucomp_to_r
, 0);
2402 rb_define_method(rb_cComplex
, "rationalize", nucomp_rationalize
, -1);
2403 rb_define_method(rb_cComplex
, "to_c", nucomp_to_c
, 0);
2404 rb_define_method(rb_cNilClass
, "to_c", nilclass_to_c
, 0);
2405 rb_define_method(rb_cNumeric
, "to_c", numeric_to_c
, 0);
2407 rb_define_method(rb_cString
, "to_c", string_to_c
, 0);
2409 rb_define_private_method(CLASS_OF(rb_cComplex
), "convert", nucomp_s_convert
, -1);
2411 rb_define_method(rb_cNumeric
, "real", numeric_real
, 0);
2412 rb_define_method(rb_cNumeric
, "imaginary", numeric_imag
, 0);
2413 rb_define_method(rb_cNumeric
, "imag", numeric_imag
, 0);
2414 rb_define_method(rb_cNumeric
, "abs2", numeric_abs2
, 0);
2415 rb_define_method(rb_cNumeric
, "arg", numeric_arg
, 0);
2416 rb_define_method(rb_cNumeric
, "angle", numeric_arg
, 0);
2417 rb_define_method(rb_cNumeric
, "phase", numeric_arg
, 0);
2418 rb_define_method(rb_cNumeric
, "rectangular", numeric_rect
, 0);
2419 rb_define_method(rb_cNumeric
, "rect", numeric_rect
, 0);
2420 rb_define_method(rb_cNumeric
, "polar", numeric_polar
, 0);
2421 rb_define_method(rb_cNumeric
, "conjugate", numeric_conj
, 0);
2422 rb_define_method(rb_cNumeric
, "conj", numeric_conj
, 0);
2424 rb_define_method(rb_cFloat
, "arg", float_arg
, 0);
2425 rb_define_method(rb_cFloat
, "angle", float_arg
, 0);
2426 rb_define_method(rb_cFloat
, "phase", float_arg
, 0);
2429 * The imaginary unit.
2431 rb_define_const(rb_cComplex
, "I",
2432 f_complex_new_bang2(rb_cComplex
, ZERO
, ONE
));
2435 rb_gc_register_mark_object(RFLOAT_0
= DBL2NUM(0.0));
2438 rb_provide("complex.so"); /* for backward compatibility */