Ruby 2.7.7p221 (2022-11-24 revision 168ec2b1e5ad0e4688e963d9de019557c78feed9)
complex.c
Go to the documentation of this file.
1/*
2 complex.c: Coded by Tadayoshi Funaba 2008-2012
3
4 This implementation is based on Keiju Ishitsuka's Complex library
5 which is written in ruby.
6*/
7
8#include "ruby/config.h"
9#if defined _MSC_VER
10/* Microsoft Visual C does not define M_PI and others by default */
11# define _USE_MATH_DEFINES 1
12#endif
13#include <math.h>
14#include "internal.h"
15#include "id.h"
16
17#define NDEBUG
18#include "ruby_assert.h"
19
20#define ZERO INT2FIX(0)
21#define ONE INT2FIX(1)
22#define TWO INT2FIX(2)
23#if USE_FLONUM
24#define RFLOAT_0 DBL2NUM(0)
25#else
26static VALUE RFLOAT_0;
27#endif
28#if defined(HAVE_SIGNBIT) && defined(__GNUC__) && defined(__sun) && \
29 !defined(signbit)
30extern int signbit(double);
31#endif
32
34
35static ID id_abs, id_arg,
37 id_real_p, id_i_real, id_i_imag,
38 id_finite_p, id_infinite_p, id_rationalize,
39 id_PI;
40#define id_to_i idTo_i
41#define id_to_r idTo_r
42#define id_negate idUMinus
43#define id_expt idPow
44#define id_to_f idTo_f
45#define id_quo idQuo
46#define id_fdiv idFdiv
47
48#define f_boolcast(x) ((x) ? Qtrue : Qfalse)
49
50#define fun1(n) \
51inline static VALUE \
52f_##n(VALUE x)\
53{\
54 return rb_funcall(x, id_##n, 0);\
55}
56
57#define fun2(n) \
58inline static VALUE \
59f_##n(VALUE x, VALUE y)\
60{\
61 return rb_funcall(x, id_##n, 1, y);\
62}
63
64#define PRESERVE_SIGNEDZERO
65
66inline static VALUE
67f_add(VALUE x, VALUE y)
68{
69 if (RB_INTEGER_TYPE_P(x) &&
71 if (FIXNUM_ZERO_P(x))
72 return y;
73 if (FIXNUM_ZERO_P(y))
74 return x;
75 return rb_int_plus(x, y);
76 }
77 else if (RB_FLOAT_TYPE_P(x) &&
79 if (FIXNUM_ZERO_P(y))
80 return x;
81 return rb_float_plus(x, y);
82 }
83 else if (RB_TYPE_P(x, T_RATIONAL) &&
85 if (FIXNUM_ZERO_P(y))
86 return x;
87 return rb_rational_plus(x, y);
88 }
89
90 return rb_funcall(x, '+', 1, y);
91}
92
93inline static VALUE
94f_div(VALUE x, VALUE y)
95{
96 if (FIXNUM_P(y) && FIX2LONG(y) == 1)
97 return x;
98 return rb_funcall(x, '/', 1, y);
99}
100
101inline static int
102f_gt_p(VALUE x, VALUE y)
103{
104 if (RB_INTEGER_TYPE_P(x)) {
105 if (FIXNUM_P(x) && FIXNUM_P(y))
106 return (SIGNED_VALUE)x > (SIGNED_VALUE)y;
107 return RTEST(rb_int_gt(x, y));
108 }
109 else if (RB_FLOAT_TYPE_P(x))
110 return RTEST(rb_float_gt(x, y));
111 else if (RB_TYPE_P(x, T_RATIONAL)) {
112 int const cmp = rb_cmpint(rb_rational_cmp(x, y), x, y);
113 return cmp > 0;
114 }
115 return RTEST(rb_funcall(x, '>', 1, y));
116}
117
118inline static VALUE
119f_mul(VALUE x, VALUE y)
120{
121 if (RB_INTEGER_TYPE_P(x) &&
123 if (FIXNUM_ZERO_P(y))
124 return ZERO;
125 if (FIXNUM_ZERO_P(x) && RB_INTEGER_TYPE_P(y))
126 return ZERO;
127 if (x == ONE) return y;
128 if (y == ONE) return x;
129 return rb_int_mul(x, y);
130 }
131 else if (RB_FLOAT_TYPE_P(x) &&
133 if (y == ONE) return x;
134 return rb_float_mul(x, y);
135 }
136 else if (RB_TYPE_P(x, T_RATIONAL) &&
138 if (y == ONE) return x;
139 return rb_rational_mul(x, y);
140 }
142 if (y == ONE) return x;
143 }
144 return rb_funcall(x, '*', 1, y);
145}
146
147inline static VALUE
148f_sub(VALUE x, VALUE y)
149{
150 if (FIXNUM_ZERO_P(y) &&
152 return x;
153 }
154 return rb_funcall(x, '-', 1, y);
155}
156
157inline static VALUE
158f_abs(VALUE x)
159{
160 if (RB_INTEGER_TYPE_P(x)) {
161 return rb_int_abs(x);
162 }
163 else if (RB_FLOAT_TYPE_P(x)) {
164 return rb_float_abs(x);
165 }
166 else if (RB_TYPE_P(x, T_RATIONAL)) {
167 return rb_rational_abs(x);
168 }
169 else if (RB_TYPE_P(x, T_COMPLEX)) {
170 return rb_complex_abs(x);
171 }
172 return rb_funcall(x, id_abs, 0);
173}
174
175static VALUE numeric_arg(VALUE self);
176static VALUE float_arg(VALUE self);
177
178inline static VALUE
179f_arg(VALUE x)
180{
181 if (RB_INTEGER_TYPE_P(x)) {
182 return numeric_arg(x);
183 }
184 else if (RB_FLOAT_TYPE_P(x)) {
185 return float_arg(x);
186 }
187 else if (RB_TYPE_P(x, T_RATIONAL)) {
188 return numeric_arg(x);
189 }
190 else if (RB_TYPE_P(x, T_COMPLEX)) {
191 return rb_complex_arg(x);
192 }
193 return rb_funcall(x, id_arg, 0);
194}
195
196inline static VALUE
198{
199 if (RB_TYPE_P(x, T_RATIONAL)) {
200 return RRATIONAL(x)->num;
201 }
202 if (RB_FLOAT_TYPE_P(x)) {
203 return rb_float_numerator(x);
204 }
205 return x;
206}
207
208inline static VALUE
210{
211 if (RB_TYPE_P(x, T_RATIONAL)) {
212 return RRATIONAL(x)->den;
213 }
214 if (RB_FLOAT_TYPE_P(x)) {
215 return rb_float_denominator(x);
216 }
217 return INT2FIX(1);
218}
219
220inline static VALUE
222{
223 if (RB_INTEGER_TYPE_P(x)) {
224 return rb_int_uminus(x);
225 }
226 else if (RB_FLOAT_TYPE_P(x)) {
227 return rb_float_uminus(x);
228 }
229 else if (RB_TYPE_P(x, T_RATIONAL)) {
230 return rb_rational_uminus(x);
231 }
232 else if (RB_TYPE_P(x, T_COMPLEX)) {
233 return rb_complex_uminus(x);
234 }
235 return rb_funcall(x, id_negate, 0);
236}
237
238static bool nucomp_real_p(VALUE self);
239
240static inline bool
241f_real_p(VALUE x)
242{
243 if (RB_INTEGER_TYPE_P(x)) {
244 return true;
245 }
246 else if (RB_FLOAT_TYPE_P(x)) {
247 return true;
248 }
249 else if (RB_TYPE_P(x, T_RATIONAL)) {
250 return true;
251 }
252 else if (RB_TYPE_P(x, T_COMPLEX)) {
253 return nucomp_real_p(x);
254 }
255 return rb_funcall(x, id_real_p, 0);
256}
257
258inline static VALUE
259f_to_i(VALUE x)
260{
261 if (RB_TYPE_P(x, T_STRING))
262 return rb_str_to_inum(x, 10, 0);
263 return rb_funcall(x, id_to_i, 0);
264}
265
266inline static VALUE
267f_to_f(VALUE x)
268{
269 if (RB_TYPE_P(x, T_STRING))
270 return DBL2NUM(rb_str_to_dbl(x, 0));
271 return rb_funcall(x, id_to_f, 0);
272}
273
274fun1(to_r)
275
276inline static int
277f_eqeq_p(VALUE x, VALUE y)
278{
279 if (FIXNUM_P(x) && FIXNUM_P(y))
280 return x == y;
281 else if (RB_FLOAT_TYPE_P(x) || RB_FLOAT_TYPE_P(y))
282 return NUM2DBL(x) == NUM2DBL(y);
283 return (int)rb_equal(x, y);
284}
285
286fun2(expt)
287fun2(fdiv)
288
289static VALUE
290f_quo(VALUE x, VALUE y)
291{
292 if (RB_INTEGER_TYPE_P(x))
293 return rb_numeric_quo(x, y);
294 if (RB_FLOAT_TYPE_P(x))
295 return rb_float_div(x, y);
296 if (RB_TYPE_P(x, T_RATIONAL))
297 return rb_numeric_quo(x, y);
298
299 return rb_funcallv(x, id_quo, 1, &y);
300}
301
302inline static int
303f_negative_p(VALUE x)
304{
305 if (RB_INTEGER_TYPE_P(x))
306 return INT_NEGATIVE_P(x);
307 else if (RB_FLOAT_TYPE_P(x))
308 return RFLOAT_VALUE(x) < 0.0;
309 else if (RB_TYPE_P(x, T_RATIONAL))
310 return INT_NEGATIVE_P(RRATIONAL(x)->num);
311 return rb_num_negative_p(x);
312}
313
314#define f_positive_p(x) (!f_negative_p(x))
315
316inline static int
317f_zero_p(VALUE x)
318{
319 if (RB_FLOAT_TYPE_P(x)) {
320 return FLOAT_ZERO_P(x);
321 }
322 else if (RB_INTEGER_TYPE_P(x)) {
323 return FIXNUM_ZERO_P(x);
324 }
325 else if (RB_TYPE_P(x, T_RATIONAL)) {
326 const VALUE num = RRATIONAL(x)->num;
327 return FIXNUM_ZERO_P(num);
328 }
329 return (int)rb_equal(x, ZERO);
330}
331
332#define f_nonzero_p(x) (!f_zero_p(x))
333
335inline static int
336f_finite_p(VALUE x)
337{
338 if (RB_INTEGER_TYPE_P(x)) {
339 return TRUE;
340 }
341 else if (RB_FLOAT_TYPE_P(x)) {
342 return (int)rb_flo_is_finite_p(x);
343 }
344 else if (RB_TYPE_P(x, T_RATIONAL)) {
345 return TRUE;
346 }
347 return RTEST(rb_funcallv(x, id_finite_p, 0, 0));
348}
349
351inline static VALUE
352f_infinite_p(VALUE x)
353{
354 if (RB_INTEGER_TYPE_P(x)) {
355 return Qnil;
356 }
357 else if (RB_FLOAT_TYPE_P(x)) {
358 return rb_flo_is_infinite_p(x);
359 }
360 else if (RB_TYPE_P(x, T_RATIONAL)) {
361 return Qnil;
362 }
363 return rb_funcallv(x, id_infinite_p, 0, 0);
364}
365
366inline static int
367f_kind_of_p(VALUE x, VALUE c)
368{
369 return (int)rb_obj_is_kind_of(x, c);
370}
371
372inline static int
373k_numeric_p(VALUE x)
374{
375 return f_kind_of_p(x, rb_cNumeric);
376}
377
378#define k_exact_p(x) (!RB_FLOAT_TYPE_P(x))
379
380#define k_exact_zero_p(x) (k_exact_p(x) && f_zero_p(x))
381
382#define get_dat1(x) \
383 struct RComplex *dat = RCOMPLEX(x)
384
385#define get_dat2(x,y) \
386 struct RComplex *adat = RCOMPLEX(x), *bdat = RCOMPLEX(y)
387
388inline static VALUE
389nucomp_s_new_internal(VALUE klass, VALUE real, VALUE imag)
390{
392
393 RCOMPLEX_SET_REAL(obj, real);
394 RCOMPLEX_SET_IMAG(obj, imag);
396
397 return (VALUE)obj;
398}
399
400static VALUE
401nucomp_s_alloc(VALUE klass)
402{
403 return nucomp_s_new_internal(klass, ZERO, ZERO);
404}
405
406inline static VALUE
407f_complex_new_bang1(VALUE klass, VALUE x)
408{
410 return nucomp_s_new_internal(klass, x, ZERO);
411}
412
413inline static VALUE
414f_complex_new_bang2(VALUE klass, VALUE x, VALUE y)
415{
418 return nucomp_s_new_internal(klass, x, y);
419}
420
421#ifdef CANONICALIZATION_FOR_MATHN
422static int canonicalization = 0;
423
425nucomp_canonicalization(int f)
426{
428}
429#else
430#define canonicalization 0
431#endif
432
433inline static void
434nucomp_real_check(VALUE num)
435{
436 if (!RB_INTEGER_TYPE_P(num) &&
437 !RB_FLOAT_TYPE_P(num) &&
438 !RB_TYPE_P(num, T_RATIONAL)) {
439 if (!k_numeric_p(num) || !f_real_p(num))
440 rb_raise(rb_eTypeError, "not a real");
441 }
442}
443
444inline static VALUE
445nucomp_s_canonicalize_internal(VALUE klass, VALUE real, VALUE imag)
446{
447 int complex_r, complex_i;
448#ifdef CANONICALIZATION_FOR_MATHN
449 if (k_exact_zero_p(imag) && canonicalization)
450 return real;
451#endif
452 complex_r = RB_TYPE_P(real, T_COMPLEX);
453 complex_i = RB_TYPE_P(imag, T_COMPLEX);
454 if (!complex_r && !complex_i) {
455 return nucomp_s_new_internal(klass, real, imag);
456 }
457 else if (!complex_r) {
458 get_dat1(imag);
459
460 return nucomp_s_new_internal(klass,
461 f_sub(real, dat->imag),
462 f_add(ZERO, dat->real));
463 }
464 else if (!complex_i) {
465 get_dat1(real);
466
467 return nucomp_s_new_internal(klass,
468 dat->real,
469 f_add(dat->imag, imag));
470 }
471 else {
472 get_dat2(real, imag);
473
474 return nucomp_s_new_internal(klass,
475 f_sub(adat->real, bdat->imag),
476 f_add(adat->imag, bdat->real));
477 }
478}
479
480/*
481 * call-seq:
482 * Complex.rect(real[, imag]) -> complex
483 * Complex.rectangular(real[, imag]) -> complex
484 *
485 * Returns a complex object which denotes the given rectangular form.
486 *
487 * Complex.rectangular(1, 2) #=> (1+2i)
488 */
489static VALUE
490nucomp_s_new(int argc, VALUE *argv, VALUE klass)
491{
492 VALUE real, imag;
493
494 switch (rb_scan_args(argc, argv, "11", &real, &imag)) {
495 case 1:
496 nucomp_real_check(real);
497 imag = ZERO;
498 break;
499 default:
500 nucomp_real_check(real);
501 nucomp_real_check(imag);
502 break;
503 }
504
505 return nucomp_s_canonicalize_internal(klass, real, imag);
506}
507
508inline static VALUE
509f_complex_new2(VALUE klass, VALUE x, VALUE y)
510{
512 return nucomp_s_canonicalize_internal(klass, x, y);
513}
514
515static VALUE nucomp_convert(VALUE klass, VALUE a1, VALUE a2, int raise);
516static VALUE nucomp_s_convert(int argc, VALUE *argv, VALUE klass);
517
518/*
519 * call-seq:
520 * Complex(x[, y], exception: true) -> numeric or nil
521 *
522 * Returns x+i*y;
523 *
524 * Complex(1, 2) #=> (1+2i)
525 * Complex('1+2i') #=> (1+2i)
526 * Complex(nil) #=> TypeError
527 * Complex(1, nil) #=> TypeError
528 *
529 * Complex(1, nil, exception: false) #=> nil
530 * Complex('1+2', exception: false) #=> nil
531 *
532 * Syntax of string form:
533 *
534 * string form = extra spaces , complex , extra spaces ;
535 * complex = real part | [ sign ] , imaginary part
536 * | real part , sign , imaginary part
537 * | rational , "@" , rational ;
538 * real part = rational ;
539 * imaginary part = imaginary unit | unsigned rational , imaginary unit ;
540 * rational = [ sign ] , unsigned rational ;
541 * unsigned rational = numerator | numerator , "/" , denominator ;
542 * numerator = integer part | fractional part | integer part , fractional part ;
543 * denominator = digits ;
544 * integer part = digits ;
545 * fractional part = "." , digits , [ ( "e" | "E" ) , [ sign ] , digits ] ;
546 * imaginary unit = "i" | "I" | "j" | "J" ;
547 * sign = "-" | "+" ;
548 * digits = digit , { digit | "_" , digit };
549 * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
550 * extra spaces = ? \s* ? ;
551 *
552 * See String#to_c.
553 */
554static VALUE
555nucomp_f_complex(int argc, VALUE *argv, VALUE klass)
556{
557 VALUE a1, a2, opts = Qnil;
558 int raise = TRUE;
559
560 if (rb_scan_args(argc, argv, "11:", &a1, &a2, &opts) == 1) {
561 a2 = Qundef;
562 }
563 if (!NIL_P(opts)) {
564 raise = rb_opts_exception_p(opts, raise);
565 }
566 if (argc > 0 && CLASS_OF(a1) == rb_cComplex && a2 == Qundef) {
567 return a1;
568 }
569 return nucomp_convert(rb_cComplex, a1, a2, raise);
570}
571
572#define imp1(n) \
573inline static VALUE \
574m_##n##_bang(VALUE x)\
575{\
576 return rb_math_##n(x);\
577}
578
580imp1(cosh)
581imp1(exp)
582
583static VALUE
584m_log_bang(VALUE x)
585{
586 return rb_math_log(1, &x);
587}
588
590imp1(sinh)
591
592static VALUE
593m_cos(VALUE x)
594{
595 if (!RB_TYPE_P(x, T_COMPLEX))
596 return m_cos_bang(x);
597 {
598 get_dat1(x);
599 return f_complex_new2(rb_cComplex,
600 f_mul(m_cos_bang(dat->real),
601 m_cosh_bang(dat->imag)),
602 f_mul(f_negate(m_sin_bang(dat->real)),
603 m_sinh_bang(dat->imag)));
604 }
605}
606
607static VALUE
608m_sin(VALUE x)
609{
610 if (!RB_TYPE_P(x, T_COMPLEX))
611 return m_sin_bang(x);
612 {
613 get_dat1(x);
614 return f_complex_new2(rb_cComplex,
615 f_mul(m_sin_bang(dat->real),
616 m_cosh_bang(dat->imag)),
617 f_mul(m_cos_bang(dat->real),
618 m_sinh_bang(dat->imag)));
619 }
620}
621
622static VALUE
623f_complex_polar(VALUE klass, VALUE x, VALUE y)
624{
627 if (f_zero_p(x) || f_zero_p(y)) {
628 if (canonicalization) return x;
629 return nucomp_s_new_internal(klass, x, RFLOAT_0);
630 }
631 if (RB_FLOAT_TYPE_P(y)) {
632 const double arg = RFLOAT_VALUE(y);
633 if (arg == M_PI) {
634 x = f_negate(x);
635 if (canonicalization) return x;
636 y = RFLOAT_0;
637 }
638 else if (arg == M_PI_2) {
639 y = x;
640 x = RFLOAT_0;
641 }
642 else if (arg == M_PI_2+M_PI) {
643 y = f_negate(x);
644 x = RFLOAT_0;
645 }
646 else if (RB_FLOAT_TYPE_P(x)) {
647 const double abs = RFLOAT_VALUE(x);
648 const double real = abs * cos(arg), imag = abs * sin(arg);
649 x = DBL2NUM(real);
650 if (canonicalization && imag == 0.0) return x;
651 y = DBL2NUM(imag);
652 }
653 else {
654 y = f_mul(x, DBL2NUM(sin(arg)));
655 x = f_mul(x, DBL2NUM(cos(arg)));
656 if (canonicalization && f_zero_p(y)) return x;
657 }
658 return nucomp_s_new_internal(klass, x, y);
659 }
660 return nucomp_s_canonicalize_internal(klass,
661 f_mul(x, m_cos(y)),
662 f_mul(x, m_sin(y)));
663}
664
665/* returns a Complex or Float of ang*PI-rotated abs */
666VALUE
668{
669 double fi;
670 const double fr = modf(ang, &fi);
671 int pos = fr == +0.5;
672
673 if (pos || fr == -0.5) {
674 if ((modf(fi / 2.0, &fi) != fr) ^ pos) abs = -abs;
676 }
677 else if (fr == 0.0) {
678 if (modf(fi / 2.0, &fi) != 0.0) abs = -abs;
679 return DBL2NUM(abs);
680 }
681 else {
682 ang *= M_PI;
683 return rb_complex_new(DBL2NUM(abs * cos(ang)), DBL2NUM(abs * sin(ang)));
684 }
685}
686
687/*
688 * call-seq:
689 * Complex.polar(abs[, arg]) -> complex
690 *
691 * Returns a complex object which denotes the given polar form.
692 *
693 * Complex.polar(3, 0) #=> (3.0+0.0i)
694 * Complex.polar(3, Math::PI/2) #=> (1.836909530733566e-16+3.0i)
695 * Complex.polar(3, Math::PI) #=> (-3.0+3.673819061467132e-16i)
696 * Complex.polar(3, -Math::PI/2) #=> (1.836909530733566e-16-3.0i)
697 */
698static VALUE
699nucomp_s_polar(int argc, VALUE *argv, VALUE klass)
700{
701 VALUE abs, arg;
702
703 switch (rb_scan_args(argc, argv, "11", &abs, &arg)) {
704 case 1:
705 nucomp_real_check(abs);
706 if (canonicalization) return abs;
707 return nucomp_s_new_internal(klass, abs, ZERO);
708 default:
709 nucomp_real_check(abs);
710 nucomp_real_check(arg);
711 break;
712 }
713 return f_complex_polar(klass, abs, arg);
714}
715
716/*
717 * call-seq:
718 * cmp.real -> real
719 *
720 * Returns the real part.
721 *
722 * Complex(7).real #=> 7
723 * Complex(9, -4).real #=> 9
724 */
725VALUE
727{
728 get_dat1(self);
729 return dat->real;
730}
731
732/*
733 * call-seq:
734 * cmp.imag -> real
735 * cmp.imaginary -> real
736 *
737 * Returns the imaginary part.
738 *
739 * Complex(7).imaginary #=> 0
740 * Complex(9, -4).imaginary #=> -4
741 */
742VALUE
744{
745 get_dat1(self);
746 return dat->imag;
747}
748
749/*
750 * call-seq:
751 * -cmp -> complex
752 *
753 * Returns negation of the value.
754 *
755 * -Complex(1, 2) #=> (-1-2i)
756 */
757VALUE
759{
760 get_dat1(self);
761 return f_complex_new2(CLASS_OF(self),
762 f_negate(dat->real), f_negate(dat->imag));
763}
764
765/*
766 * call-seq:
767 * cmp + numeric -> complex
768 *
769 * Performs addition.
770 *
771 * Complex(2, 3) + Complex(2, 3) #=> (4+6i)
772 * Complex(900) + Complex(1) #=> (901+0i)
773 * Complex(-2, 9) + Complex(-9, 2) #=> (-11+11i)
774 * Complex(9, 8) + 4 #=> (13+8i)
775 * Complex(20, 9) + 9.8 #=> (29.8+9i)
776 */
777VALUE
779{
780 if (RB_TYPE_P(other, T_COMPLEX)) {
781 VALUE real, imag;
782
783 get_dat2(self, other);
784
785 real = f_add(adat->real, bdat->real);
786 imag = f_add(adat->imag, bdat->imag);
787
788 return f_complex_new2(CLASS_OF(self), real, imag);
789 }
790 if (k_numeric_p(other) && f_real_p(other)) {
791 get_dat1(self);
792
793 return f_complex_new2(CLASS_OF(self),
794 f_add(dat->real, other), dat->imag);
795 }
796 return rb_num_coerce_bin(self, other, '+');
797}
798
799/*
800 * call-seq:
801 * cmp - numeric -> complex
802 *
803 * Performs subtraction.
804 *
805 * Complex(2, 3) - Complex(2, 3) #=> (0+0i)
806 * Complex(900) - Complex(1) #=> (899+0i)
807 * Complex(-2, 9) - Complex(-9, 2) #=> (7+7i)
808 * Complex(9, 8) - 4 #=> (5+8i)
809 * Complex(20, 9) - 9.8 #=> (10.2+9i)
810 */
811VALUE
813{
814 if (RB_TYPE_P(other, T_COMPLEX)) {
815 VALUE real, imag;
816
817 get_dat2(self, other);
818
819 real = f_sub(adat->real, bdat->real);
820 imag = f_sub(adat->imag, bdat->imag);
821
822 return f_complex_new2(CLASS_OF(self), real, imag);
823 }
824 if (k_numeric_p(other) && f_real_p(other)) {
825 get_dat1(self);
826
827 return f_complex_new2(CLASS_OF(self),
828 f_sub(dat->real, other), dat->imag);
829 }
830 return rb_num_coerce_bin(self, other, '-');
831}
832
833static VALUE
834safe_mul(VALUE a, VALUE b, int az, int bz)
835{
836 double v;
837 if (!az && bz && RB_FLOAT_TYPE_P(a) && (v = RFLOAT_VALUE(a), !isnan(v))) {
838 a = signbit(v) ? DBL2NUM(-1.0) : DBL2NUM(1.0);
839 }
840 if (!bz && az && RB_FLOAT_TYPE_P(b) && (v = RFLOAT_VALUE(b), !isnan(v))) {
841 b = signbit(v) ? DBL2NUM(-1.0) : DBL2NUM(1.0);
842 }
843 return f_mul(a, b);
844}
845
846static void
847comp_mul(VALUE areal, VALUE aimag, VALUE breal, VALUE bimag, VALUE *real, VALUE *imag)
848{
849 int arzero = f_zero_p(areal);
850 int aizero = f_zero_p(aimag);
851 int brzero = f_zero_p(breal);
852 int bizero = f_zero_p(bimag);
853 *real = f_sub(safe_mul(areal, breal, arzero, brzero),
854 safe_mul(aimag, bimag, aizero, bizero));
855 *imag = f_add(safe_mul(areal, bimag, arzero, bizero),
856 safe_mul(aimag, breal, aizero, brzero));
857}
858
859/*
860 * call-seq:
861 * cmp * numeric -> complex
862 *
863 * Performs multiplication.
864 *
865 * Complex(2, 3) * Complex(2, 3) #=> (-5+12i)
866 * Complex(900) * Complex(1) #=> (900+0i)
867 * Complex(-2, 9) * Complex(-9, 2) #=> (0-85i)
868 * Complex(9, 8) * 4 #=> (36+32i)
869 * Complex(20, 9) * 9.8 #=> (196.0+88.2i)
870 */
871VALUE
873{
874 if (RB_TYPE_P(other, T_COMPLEX)) {
875 VALUE real, imag;
876 get_dat2(self, other);
877
878 comp_mul(adat->real, adat->imag, bdat->real, bdat->imag, &real, &imag);
879
880 return f_complex_new2(CLASS_OF(self), real, imag);
881 }
882 if (k_numeric_p(other) && f_real_p(other)) {
883 get_dat1(self);
884
885 return f_complex_new2(CLASS_OF(self),
886 f_mul(dat->real, other),
887 f_mul(dat->imag, other));
888 }
889 return rb_num_coerce_bin(self, other, '*');
890}
891
892inline static VALUE
893f_divide(VALUE self, VALUE other,
894 VALUE (*func)(VALUE, VALUE), ID id)
895{
896 if (RB_TYPE_P(other, T_COMPLEX)) {
897 VALUE r, n, x, y;
898 int flo;
899 get_dat2(self, other);
900
901 flo = (RB_FLOAT_TYPE_P(adat->real) || RB_FLOAT_TYPE_P(adat->imag) ||
902 RB_FLOAT_TYPE_P(bdat->real) || RB_FLOAT_TYPE_P(bdat->imag));
903
904 if (f_gt_p(f_abs(bdat->real), f_abs(bdat->imag))) {
905 r = (*func)(bdat->imag, bdat->real);
906 n = f_mul(bdat->real, f_add(ONE, f_mul(r, r)));
907 x = (*func)(f_add(adat->real, f_mul(adat->imag, r)), n);
908 y = (*func)(f_sub(adat->imag, f_mul(adat->real, r)), n);
909 }
910 else {
911 r = (*func)(bdat->real, bdat->imag);
912 n = f_mul(bdat->imag, f_add(ONE, f_mul(r, r)));
913 x = (*func)(f_add(f_mul(adat->real, r), adat->imag), n);
914 y = (*func)(f_sub(f_mul(adat->imag, r), adat->real), n);
915 }
916 if (!flo) {
919 }
920 return f_complex_new2(CLASS_OF(self), x, y);
921 }
922 if (k_numeric_p(other) && f_real_p(other)) {
923 VALUE x, y;
924 get_dat1(self);
925 x = rb_rational_canonicalize((*func)(dat->real, other));
926 y = rb_rational_canonicalize((*func)(dat->imag, other));
927 return f_complex_new2(CLASS_OF(self), x, y);
928 }
929 return rb_num_coerce_bin(self, other, id);
930}
931
932#define rb_raise_zerodiv() rb_raise(rb_eZeroDivError, "divided by 0")
933
934/*
935 * call-seq:
936 * cmp / numeric -> complex
937 * cmp.quo(numeric) -> complex
938 *
939 * Performs division.
940 *
941 * Complex(2, 3) / Complex(2, 3) #=> ((1/1)+(0/1)*i)
942 * Complex(900) / Complex(1) #=> ((900/1)+(0/1)*i)
943 * Complex(-2, 9) / Complex(-9, 2) #=> ((36/85)-(77/85)*i)
944 * Complex(9, 8) / 4 #=> ((9/4)+(2/1)*i)
945 * Complex(20, 9) / 9.8 #=> (2.0408163265306123+0.9183673469387754i)
946 */
947VALUE
949{
950 return f_divide(self, other, f_quo, id_quo);
951}
952
953#define nucomp_quo rb_complex_div
954
955/*
956 * call-seq:
957 * cmp.fdiv(numeric) -> complex
958 *
959 * Performs division as each part is a float, never returns a float.
960 *
961 * Complex(11, 22).fdiv(3) #=> (3.6666666666666665+7.333333333333333i)
962 */
963static VALUE
964nucomp_fdiv(VALUE self, VALUE other)
965{
966 return f_divide(self, other, f_fdiv, id_fdiv);
967}
968
969inline static VALUE
971{
972 return f_quo(ONE, x);
973}
974
975/*
976 * call-seq:
977 * cmp ** numeric -> complex
978 *
979 * Performs exponentiation.
980 *
981 * Complex('i') ** 2 #=> (-1+0i)
982 * Complex(-8) ** Rational(1, 3) #=> (1.0000000000000002+1.7320508075688772i)
983 */
984VALUE
986{
987 if (k_numeric_p(other) && k_exact_zero_p(other))
988 return f_complex_new_bang1(CLASS_OF(self), ONE);
989
990 if (RB_TYPE_P(other, T_RATIONAL) && RRATIONAL(other)->den == LONG2FIX(1))
991 other = RRATIONAL(other)->num; /* c14n */
992
993 if (RB_TYPE_P(other, T_COMPLEX)) {
994 get_dat1(other);
995
996 if (k_exact_zero_p(dat->imag))
997 other = dat->real; /* c14n */
998 }
999
1000 if (RB_TYPE_P(other, T_COMPLEX)) {
1001 VALUE r, theta, nr, ntheta;
1002
1003 get_dat1(other);
1004
1005 r = f_abs(self);
1006 theta = f_arg(self);
1007
1008 nr = m_exp_bang(f_sub(f_mul(dat->real, m_log_bang(r)),
1009 f_mul(dat->imag, theta)));
1010 ntheta = f_add(f_mul(theta, dat->real),
1011 f_mul(dat->imag, m_log_bang(r)));
1012 return f_complex_polar(CLASS_OF(self), nr, ntheta);
1013 }
1014 if (FIXNUM_P(other)) {
1015 long n = FIX2LONG(other);
1016 if (n == 0) {
1017 return nucomp_s_new_internal(CLASS_OF(self), ONE, ZERO);
1018 }
1019 if (n < 0) {
1020 self = f_reciprocal(self);
1021 other = rb_int_uminus(other);
1022 n = -n;
1023 }
1024 {
1025 get_dat1(self);
1026 VALUE xr = dat->real, xi = dat->imag, zr = xr, zi = xi;
1027
1028 if (f_zero_p(xi)) {
1029 zr = rb_num_pow(zr, other);
1030 }
1031 else if (f_zero_p(xr)) {
1032 zi = rb_num_pow(zi, other);
1033 if (n & 2) zi = f_negate(zi);
1034 if (!(n & 1)) {
1035 VALUE tmp = zr;
1036 zr = zi;
1037 zi = tmp;
1038 }
1039 }
1040 else {
1041 while (--n) {
1042 long q, r;
1043
1044 for (; q = n / 2, r = n % 2, r == 0; n = q) {
1045 VALUE tmp = f_sub(f_mul(xr, xr), f_mul(xi, xi));
1046 xi = f_mul(f_mul(TWO, xr), xi);
1047 xr = tmp;
1048 }
1049 comp_mul(zr, zi, xr, xi, &zr, &zi);
1050 }
1051 }
1052 return nucomp_s_new_internal(CLASS_OF(self), zr, zi);
1053 }
1054 }
1055 if (k_numeric_p(other) && f_real_p(other)) {
1056 VALUE r, theta;
1057
1058 if (RB_TYPE_P(other, T_BIGNUM))
1059 rb_warn("in a**b, b may be too big");
1060
1061 r = f_abs(self);
1062 theta = f_arg(self);
1063
1064 return f_complex_polar(CLASS_OF(self), f_expt(r, other),
1065 f_mul(theta, other));
1066 }
1067 return rb_num_coerce_bin(self, other, id_expt);
1068}
1069
1070/*
1071 * call-seq:
1072 * cmp == object -> true or false
1073 *
1074 * Returns true if cmp equals object numerically.
1075 *
1076 * Complex(2, 3) == Complex(2, 3) #=> true
1077 * Complex(5) == 5 #=> true
1078 * Complex(0) == 0.0 #=> true
1079 * Complex('1/3') == 0.33 #=> false
1080 * Complex('1/2') == '1/2' #=> false
1081 */
1082static VALUE
1083nucomp_eqeq_p(VALUE self, VALUE other)
1084{
1085 if (RB_TYPE_P(other, T_COMPLEX)) {
1086 get_dat2(self, other);
1087
1088 return f_boolcast(f_eqeq_p(adat->real, bdat->real) &&
1089 f_eqeq_p(adat->imag, bdat->imag));
1090 }
1091 if (k_numeric_p(other) && f_real_p(other)) {
1092 get_dat1(self);
1093
1094 return f_boolcast(f_eqeq_p(dat->real, other) && f_zero_p(dat->imag));
1095 }
1096 return f_boolcast(f_eqeq_p(other, self));
1097}
1098
1099static bool
1100nucomp_real_p(VALUE self)
1101{
1102 get_dat1(self);
1103 return(f_zero_p(dat->imag) ? true : false);
1104}
1105
1106/*
1107 * call-seq:
1108 * cmp <=> object -> 0, 1, -1, or nil
1109 *
1110 * If +cmp+'s imaginary part is zero, and +object+ is also a
1111 * real number (or a Complex number where the imaginary part is zero),
1112 * compare the real part of +cmp+ to object. Otherwise, return nil.
1113 *
1114 * Complex(2, 3) <=> Complex(2, 3) #=> nil
1115 * Complex(2, 3) <=> 1 #=> nil
1116 * Complex(2) <=> 1 #=> 1
1117 * Complex(2) <=> 2 #=> 0
1118 * Complex(2) <=> 3 #=> -1
1119 */
1120static VALUE
1121nucomp_cmp(VALUE self, VALUE other)
1122{
1123 if (nucomp_real_p(self) && k_numeric_p(other)) {
1124 if (RB_TYPE_P(other, T_COMPLEX) && nucomp_real_p(other)) {
1125 get_dat2(self, other);
1126 return rb_funcall(adat->real, idCmp, 1, bdat->real);
1127 }
1128 else if (f_real_p(other)) {
1129 get_dat1(self);
1130 return rb_funcall(dat->real, idCmp, 1, other);
1131 }
1132 }
1133 return Qnil;
1134}
1135
1136/* :nodoc: */
1137static VALUE
1138nucomp_coerce(VALUE self, VALUE other)
1139{
1140 if (RB_TYPE_P(other, T_COMPLEX))
1141 return rb_assoc_new(other, self);
1142 if (k_numeric_p(other) && f_real_p(other))
1143 return rb_assoc_new(f_complex_new_bang1(CLASS_OF(self), other), self);
1144
1145 rb_raise(rb_eTypeError, "%"PRIsVALUE" can't be coerced into %"PRIsVALUE,
1146 rb_obj_class(other), rb_obj_class(self));
1147 return Qnil;
1148}
1149
1150/*
1151 * call-seq:
1152 * cmp.abs -> real
1153 * cmp.magnitude -> real
1154 *
1155 * Returns the absolute part of its polar form.
1156 *
1157 * Complex(-1).abs #=> 1
1158 * Complex(3.0, -4.0).abs #=> 5.0
1159 */
1160VALUE
1162{
1163 get_dat1(self);
1164
1165 if (f_zero_p(dat->real)) {
1166 VALUE a = f_abs(dat->imag);
1167 if (RB_FLOAT_TYPE_P(dat->real) && !RB_FLOAT_TYPE_P(dat->imag))
1168 a = f_to_f(a);
1169 return a;
1170 }
1171 if (f_zero_p(dat->imag)) {
1172 VALUE a = f_abs(dat->real);
1173 if (!RB_FLOAT_TYPE_P(dat->real) && RB_FLOAT_TYPE_P(dat->imag))
1174 a = f_to_f(a);
1175 return a;
1176 }
1177 return rb_math_hypot(dat->real, dat->imag);
1178}
1179
1180/*
1181 * call-seq:
1182 * cmp.abs2 -> real
1183 *
1184 * Returns square of the absolute value.
1185 *
1186 * Complex(-1).abs2 #=> 1
1187 * Complex(3.0, -4.0).abs2 #=> 25.0
1188 */
1189static VALUE
1190nucomp_abs2(VALUE self)
1191{
1192 get_dat1(self);
1193 return f_add(f_mul(dat->real, dat->real),
1194 f_mul(dat->imag, dat->imag));
1195}
1196
1197/*
1198 * call-seq:
1199 * cmp.arg -> float
1200 * cmp.angle -> float
1201 * cmp.phase -> float
1202 *
1203 * Returns the angle part of its polar form.
1204 *
1205 * Complex.polar(3, Math::PI/2).arg #=> 1.5707963267948966
1206 */
1207VALUE
1209{
1210 get_dat1(self);
1211 return rb_math_atan2(dat->imag, dat->real);
1212}
1213
1214/*
1215 * call-seq:
1216 * cmp.rect -> array
1217 * cmp.rectangular -> array
1218 *
1219 * Returns an array; [cmp.real, cmp.imag].
1220 *
1221 * Complex(1, 2).rectangular #=> [1, 2]
1222 */
1223static VALUE
1224nucomp_rect(VALUE self)
1225{
1226 get_dat1(self);
1227 return rb_assoc_new(dat->real, dat->imag);
1228}
1229
1230/*
1231 * call-seq:
1232 * cmp.polar -> array
1233 *
1234 * Returns an array; [cmp.abs, cmp.arg].
1235 *
1236 * Complex(1, 2).polar #=> [2.23606797749979, 1.1071487177940904]
1237 */
1238static VALUE
1239nucomp_polar(VALUE self)
1240{
1241 return rb_assoc_new(f_abs(self), f_arg(self));
1242}
1243
1244/*
1245 * call-seq:
1246 * cmp.conj -> complex
1247 * cmp.conjugate -> complex
1248 *
1249 * Returns the complex conjugate.
1250 *
1251 * Complex(1, 2).conjugate #=> (1-2i)
1252 */
1253VALUE
1255{
1256 get_dat1(self);
1257 return f_complex_new2(CLASS_OF(self), dat->real, f_negate(dat->imag));
1258}
1259
1260/*
1261 * call-seq:
1262 * Complex(1).real? -> false
1263 * Complex(1, 2).real? -> false
1264 *
1265 * Returns false, even if the complex number has no imaginary part.
1266 */
1267static VALUE
1268nucomp_false(VALUE self)
1269{
1270 return Qfalse;
1271}
1272
1273/*
1274 * call-seq:
1275 * cmp.denominator -> integer
1276 *
1277 * Returns the denominator (lcm of both denominator - real and imag).
1278 *
1279 * See numerator.
1280 */
1281static VALUE
1282nucomp_denominator(VALUE self)
1283{
1284 get_dat1(self);
1285 return rb_lcm(f_denominator(dat->real), f_denominator(dat->imag));
1286}
1287
1288/*
1289 * call-seq:
1290 * cmp.numerator -> numeric
1291 *
1292 * Returns the numerator.
1293 *
1294 * 1 2 3+4i <- numerator
1295 * - + -i -> ----
1296 * 2 3 6 <- denominator
1297 *
1298 * c = Complex('1/2+2/3i') #=> ((1/2)+(2/3)*i)
1299 * n = c.numerator #=> (3+4i)
1300 * d = c.denominator #=> 6
1301 * n / d #=> ((1/2)+(2/3)*i)
1302 * Complex(Rational(n.real, d), Rational(n.imag, d))
1303 * #=> ((1/2)+(2/3)*i)
1304 * See denominator.
1305 */
1306static VALUE
1307nucomp_numerator(VALUE self)
1308{
1309 VALUE cd;
1310
1311 get_dat1(self);
1312
1313 cd = nucomp_denominator(self);
1314 return f_complex_new2(CLASS_OF(self),
1315 f_mul(f_numerator(dat->real),
1316 f_div(cd, f_denominator(dat->real))),
1317 f_mul(f_numerator(dat->imag),
1318 f_div(cd, f_denominator(dat->imag))));
1319}
1320
1321/* :nodoc: */
1322static VALUE
1323nucomp_hash(VALUE self)
1324{
1325 st_index_t v, h[2];
1326 VALUE n;
1327
1328 get_dat1(self);
1329 n = rb_hash(dat->real);
1330 h[0] = NUM2LONG(n);
1331 n = rb_hash(dat->imag);
1332 h[1] = NUM2LONG(n);
1333 v = rb_memhash(h, sizeof(h));
1334 return ST2FIX(v);
1335}
1336
1337/* :nodoc: */
1338static VALUE
1339nucomp_eql_p(VALUE self, VALUE other)
1340{
1341 if (RB_TYPE_P(other, T_COMPLEX)) {
1342 get_dat2(self, other);
1343
1344 return f_boolcast((CLASS_OF(adat->real) == CLASS_OF(bdat->real)) &&
1345 (CLASS_OF(adat->imag) == CLASS_OF(bdat->imag)) &&
1346 f_eqeq_p(self, other));
1347
1348 }
1349 return Qfalse;
1350}
1351
1352inline static int
1353f_signbit(VALUE x)
1354{
1355 if (RB_FLOAT_TYPE_P(x)) {
1356 double f = RFLOAT_VALUE(x);
1357 return !isnan(f) && signbit(f);
1358 }
1359 return f_negative_p(x);
1360}
1361
1362inline static int
1363f_tpositive_p(VALUE x)
1364{
1365 return !f_signbit(x);
1366}
1367
1368static VALUE
1369f_format(VALUE self, VALUE (*func)(VALUE))
1370{
1371 VALUE s;
1372 int impos;
1373
1374 get_dat1(self);
1375
1376 impos = f_tpositive_p(dat->imag);
1377
1378 s = (*func)(dat->real);
1379 rb_str_cat2(s, !impos ? "-" : "+");
1380
1381 rb_str_concat(s, (*func)(f_abs(dat->imag)));
1382 if (!rb_isdigit(RSTRING_PTR(s)[RSTRING_LEN(s) - 1]))
1383 rb_str_cat2(s, "*");
1384 rb_str_cat2(s, "i");
1385
1386 return s;
1387}
1388
1389/*
1390 * call-seq:
1391 * cmp.to_s -> string
1392 *
1393 * Returns the value as a string.
1394 *
1395 * Complex(2).to_s #=> "2+0i"
1396 * Complex('-8/6').to_s #=> "-4/3+0i"
1397 * Complex('1/2i').to_s #=> "0+1/2i"
1398 * Complex(0, Float::INFINITY).to_s #=> "0+Infinity*i"
1399 * Complex(Float::NAN, Float::NAN).to_s #=> "NaN+NaN*i"
1400 */
1401static VALUE
1402nucomp_to_s(VALUE self)
1403{
1404 return f_format(self, rb_String);
1405}
1406
1407/*
1408 * call-seq:
1409 * cmp.inspect -> string
1410 *
1411 * Returns the value as a string for inspection.
1412 *
1413 * Complex(2).inspect #=> "(2+0i)"
1414 * Complex('-8/6').inspect #=> "((-4/3)+0i)"
1415 * Complex('1/2i').inspect #=> "(0+(1/2)*i)"
1416 * Complex(0, Float::INFINITY).inspect #=> "(0+Infinity*i)"
1417 * Complex(Float::NAN, Float::NAN).inspect #=> "(NaN+NaN*i)"
1418 */
1419static VALUE
1420nucomp_inspect(VALUE self)
1421{
1422 VALUE s;
1423
1424 s = rb_usascii_str_new2("(");
1425 rb_str_concat(s, f_format(self, rb_inspect));
1426 rb_str_cat2(s, ")");
1427
1428 return s;
1429}
1430
1431#define FINITE_TYPE_P(v) (RB_INTEGER_TYPE_P(v) || RB_TYPE_P(v, T_RATIONAL))
1432
1433/*
1434 * call-seq:
1435 * cmp.finite? -> true or false
1436 *
1437 * Returns +true+ if +cmp+'s real and imaginary parts are both finite numbers,
1438 * otherwise returns +false+.
1439 */
1440static VALUE
1441rb_complex_finite_p(VALUE self)
1442{
1443 get_dat1(self);
1444
1445 if (f_finite_p(dat->real) && f_finite_p(dat->imag)) {
1446 return Qtrue;
1447 }
1448 return Qfalse;
1449}
1450
1451/*
1452 * call-seq:
1453 * cmp.infinite? -> nil or 1
1454 *
1455 * Returns +1+ if +cmp+'s real or imaginary part is an infinite number,
1456 * otherwise returns +nil+.
1457 *
1458 * For example:
1459 *
1460 * (1+1i).infinite? #=> nil
1461 * (Float::INFINITY + 1i).infinite? #=> 1
1462 */
1463static VALUE
1464rb_complex_infinite_p(VALUE self)
1465{
1466 get_dat1(self);
1467
1468 if (NIL_P(f_infinite_p(dat->real)) && NIL_P(f_infinite_p(dat->imag))) {
1469 return Qnil;
1470 }
1471 return ONE;
1472}
1473
1474/* :nodoc: */
1475static VALUE
1476nucomp_dumper(VALUE self)
1477{
1478 return self;
1479}
1480
1481/* :nodoc: */
1482static VALUE
1483nucomp_loader(VALUE self, VALUE a)
1484{
1485 get_dat1(self);
1486
1487 RCOMPLEX_SET_REAL(dat, rb_ivar_get(a, id_i_real));
1488 RCOMPLEX_SET_IMAG(dat, rb_ivar_get(a, id_i_imag));
1489 OBJ_FREEZE_RAW(self);
1490
1491 return self;
1492}
1493
1494/* :nodoc: */
1495static VALUE
1496nucomp_marshal_dump(VALUE self)
1497{
1498 VALUE a;
1499 get_dat1(self);
1500
1501 a = rb_assoc_new(dat->real, dat->imag);
1502 rb_copy_generic_ivar(a, self);
1503 return a;
1504}
1505
1506/* :nodoc: */
1507static VALUE
1508nucomp_marshal_load(VALUE self, VALUE a)
1509{
1510 Check_Type(a, T_ARRAY);
1511 if (RARRAY_LEN(a) != 2)
1512 rb_raise(rb_eArgError, "marshaled complex must have an array whose length is 2 but %ld", RARRAY_LEN(a));
1513 rb_ivar_set(self, id_i_real, RARRAY_AREF(a, 0));
1514 rb_ivar_set(self, id_i_imag, RARRAY_AREF(a, 1));
1515 return self;
1516}
1517
1518/* --- */
1519
1520VALUE
1522{
1523 return nucomp_s_new_internal(rb_cComplex, x, y);
1524}
1525
1526VALUE
1528{
1529 return nucomp_s_canonicalize_internal(rb_cComplex, x, y);
1530}
1531
1532VALUE
1534{
1535 return f_complex_polar(rb_cComplex, x, y);
1536}
1537
1538VALUE
1540{
1541 return rb_complex_new_polar(x, y);
1542}
1543
1544VALUE
1546{
1547 VALUE a[2];
1548 a[0] = x;
1549 a[1] = y;
1550 return nucomp_s_convert(2, a, rb_cComplex);
1551}
1552
1560VALUE
1561rb_dbl_complex_new(double real, double imag)
1562{
1563 return rb_complex_raw(DBL2NUM(real), DBL2NUM(imag));
1564}
1565
1566/*
1567 * call-seq:
1568 * cmp.to_i -> integer
1569 *
1570 * Returns the value as an integer if possible (the imaginary part
1571 * should be exactly zero).
1572 *
1573 * Complex(1, 0).to_i #=> 1
1574 * Complex(1, 0.0).to_i # RangeError
1575 * Complex(1, 2).to_i # RangeError
1576 */
1577static VALUE
1578nucomp_to_i(VALUE self)
1579{
1580 get_dat1(self);
1581
1582 if (!k_exact_zero_p(dat->imag)) {
1583 rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Integer",
1584 self);
1585 }
1586 return f_to_i(dat->real);
1587}
1588
1589/*
1590 * call-seq:
1591 * cmp.to_f -> float
1592 *
1593 * Returns the value as a float if possible (the imaginary part should
1594 * be exactly zero).
1595 *
1596 * Complex(1, 0).to_f #=> 1.0
1597 * Complex(1, 0.0).to_f # RangeError
1598 * Complex(1, 2).to_f # RangeError
1599 */
1600static VALUE
1601nucomp_to_f(VALUE self)
1602{
1603 get_dat1(self);
1604
1605 if (!k_exact_zero_p(dat->imag)) {
1606 rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Float",
1607 self);
1608 }
1609 return f_to_f(dat->real);
1610}
1611
1612/*
1613 * call-seq:
1614 * cmp.to_r -> rational
1615 *
1616 * Returns the value as a rational if possible (the imaginary part
1617 * should be exactly zero).
1618 *
1619 * Complex(1, 0).to_r #=> (1/1)
1620 * Complex(1, 0.0).to_r # RangeError
1621 * Complex(1, 2).to_r # RangeError
1622 *
1623 * See rationalize.
1624 */
1625static VALUE
1626nucomp_to_r(VALUE self)
1627{
1628 get_dat1(self);
1629
1630 if (!k_exact_zero_p(dat->imag)) {
1631 rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Rational",
1632 self);
1633 }
1634 return f_to_r(dat->real);
1635}
1636
1637/*
1638 * call-seq:
1639 * cmp.rationalize([eps]) -> rational
1640 *
1641 * Returns the value as a rational if possible (the imaginary part
1642 * should be exactly zero).
1643 *
1644 * Complex(1.0/3, 0).rationalize #=> (1/3)
1645 * Complex(1, 0.0).rationalize # RangeError
1646 * Complex(1, 2).rationalize # RangeError
1647 *
1648 * See to_r.
1649 */
1650static VALUE
1651nucomp_rationalize(int argc, VALUE *argv, VALUE self)
1652{
1653 get_dat1(self);
1654
1655 rb_check_arity(argc, 0, 1);
1656
1657 if (!k_exact_zero_p(dat->imag)) {
1658 rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Rational",
1659 self);
1660 }
1661 return rb_funcallv(dat->real, id_rationalize, argc, argv);
1662}
1663
1664/*
1665 * call-seq:
1666 * complex.to_c -> self
1667 *
1668 * Returns self.
1669 *
1670 * Complex(2).to_c #=> (2+0i)
1671 * Complex(-8, 6).to_c #=> (-8+6i)
1672 */
1673static VALUE
1674nucomp_to_c(VALUE self)
1675{
1676 return self;
1677}
1678
1679/*
1680 * call-seq:
1681 * nil.to_c -> (0+0i)
1682 *
1683 * Returns zero as a complex.
1684 */
1685static VALUE
1686nilclass_to_c(VALUE self)
1687{
1688 return rb_complex_new1(INT2FIX(0));
1689}
1690
1691/*
1692 * call-seq:
1693 * num.to_c -> complex
1694 *
1695 * Returns the value as a complex.
1696 */
1697static VALUE
1698numeric_to_c(VALUE self)
1699{
1700 return rb_complex_new1(self);
1701}
1702
1703#include <ctype.h>
1704
1705inline static int
1706issign(int c)
1707{
1708 return (c == '-' || c == '+');
1709}
1710
1711static int
1712read_sign(const char **s,
1713 char **b)
1714{
1715 int sign = '?';
1716
1717 if (issign(**s)) {
1718 sign = **b = **s;
1719 (*s)++;
1720 (*b)++;
1721 }
1722 return sign;
1723}
1724
1725inline static int
1726isdecimal(int c)
1727{
1728 return isdigit((unsigned char)c);
1729}
1730
1731static int
1732read_digits(const char **s, int strict,
1733 char **b)
1734{
1735 int us = 1;
1736
1737 if (!isdecimal(**s))
1738 return 0;
1739
1740 while (isdecimal(**s) || **s == '_') {
1741 if (**s == '_') {
1742 if (strict) {
1743 if (us)
1744 return 0;
1745 }
1746 us = 1;
1747 }
1748 else {
1749 **b = **s;
1750 (*b)++;
1751 us = 0;
1752 }
1753 (*s)++;
1754 }
1755 if (us)
1756 do {
1757 (*s)--;
1758 } while (**s == '_');
1759 return 1;
1760}
1761
1762inline static int
1763islettere(int c)
1764{
1765 return (c == 'e' || c == 'E');
1766}
1767
1768static int
1769read_num(const char **s, int strict,
1770 char **b)
1771{
1772 if (**s != '.') {
1773 if (!read_digits(s, strict, b))
1774 return 0;
1775 }
1776
1777 if (**s == '.') {
1778 **b = **s;
1779 (*s)++;
1780 (*b)++;
1781 if (!read_digits(s, strict, b)) {
1782 (*b)--;
1783 return 0;
1784 }
1785 }
1786
1787 if (islettere(**s)) {
1788 **b = **s;
1789 (*s)++;
1790 (*b)++;
1791 read_sign(s, b);
1792 if (!read_digits(s, strict, b)) {
1793 (*b)--;
1794 return 0;
1795 }
1796 }
1797 return 1;
1798}
1799
1800inline static int
1801read_den(const char **s, int strict,
1802 char **b)
1803{
1804 if (!read_digits(s, strict, b))
1805 return 0;
1806 return 1;
1807}
1808
1809static int
1810read_rat_nos(const char **s, int strict,
1811 char **b)
1812{
1813 if (!read_num(s, strict, b))
1814 return 0;
1815 if (**s == '/') {
1816 **b = **s;
1817 (*s)++;
1818 (*b)++;
1819 if (!read_den(s, strict, b)) {
1820 (*b)--;
1821 return 0;
1822 }
1823 }
1824 return 1;
1825}
1826
1827static int
1828read_rat(const char **s, int strict,
1829 char **b)
1830{
1831 read_sign(s, b);
1832 if (!read_rat_nos(s, strict, b))
1833 return 0;
1834 return 1;
1835}
1836
1837inline static int
1838isimagunit(int c)
1839{
1840 return (c == 'i' || c == 'I' ||
1841 c == 'j' || c == 'J');
1842}
1843
1844static VALUE
1845str2num(char *s)
1846{
1847 if (strchr(s, '/'))
1848 return rb_cstr_to_rat(s, 0);
1849 if (strpbrk(s, ".eE"))
1850 return DBL2NUM(rb_cstr_to_dbl(s, 0));
1851 return rb_cstr_to_inum(s, 10, 0);
1852}
1853
1854static int
1855read_comp(const char **s, int strict,
1856 VALUE *ret, char **b)
1857{
1858 char *bb;
1859 int sign;
1860 VALUE num, num2;
1861
1862 bb = *b;
1863
1864 sign = read_sign(s, b);
1865
1866 if (isimagunit(**s)) {
1867 (*s)++;
1868 num = INT2FIX((sign == '-') ? -1 : + 1);
1869 *ret = rb_complex_new2(ZERO, num);
1870 return 1; /* e.g. "i" */
1871 }
1872
1873 if (!read_rat_nos(s, strict, b)) {
1874 **b = '\0';
1875 num = str2num(bb);
1876 *ret = rb_complex_new2(num, ZERO);
1877 return 0; /* e.g. "-" */
1878 }
1879 **b = '\0';
1880 num = str2num(bb);
1881
1882 if (isimagunit(**s)) {
1883 (*s)++;
1884 *ret = rb_complex_new2(ZERO, num);
1885 return 1; /* e.g. "3i" */
1886 }
1887
1888 if (**s == '@') {
1889 int st;
1890
1891 (*s)++;
1892 bb = *b;
1893 st = read_rat(s, strict, b);
1894 **b = '\0';
1895 if (strlen(bb) < 1 ||
1896 !isdecimal(*(bb + strlen(bb) - 1))) {
1897 *ret = rb_complex_new2(num, ZERO);
1898 return 0; /* e.g. "1@-" */
1899 }
1900 num2 = str2num(bb);
1901 *ret = rb_complex_new_polar(num, num2);
1902 if (!st)
1903 return 0; /* e.g. "1@2." */
1904 else
1905 return 1; /* e.g. "1@2" */
1906 }
1907
1908 if (issign(**s)) {
1909 bb = *b;
1910 sign = read_sign(s, b);
1911 if (isimagunit(**s))
1912 num2 = INT2FIX((sign == '-') ? -1 : + 1);
1913 else {
1914 if (!read_rat_nos(s, strict, b)) {
1915 *ret = rb_complex_new2(num, ZERO);
1916 return 0; /* e.g. "1+xi" */
1917 }
1918 **b = '\0';
1919 num2 = str2num(bb);
1920 }
1921 if (!isimagunit(**s)) {
1922 *ret = rb_complex_new2(num, ZERO);
1923 return 0; /* e.g. "1+3x" */
1924 }
1925 (*s)++;
1926 *ret = rb_complex_new2(num, num2);
1927 return 1; /* e.g. "1+2i" */
1928 }
1929 /* !(@, - or +) */
1930 {
1931 *ret = rb_complex_new2(num, ZERO);
1932 return 1; /* e.g. "3" */
1933 }
1934}
1935
1936inline static void
1937skip_ws(const char **s)
1938{
1939 while (isspace((unsigned char)**s))
1940 (*s)++;
1941}
1942
1943static int
1944parse_comp(const char *s, int strict, VALUE *num)
1945{
1946 char *buf, *b;
1947 VALUE tmp;
1948 int ret = 1;
1949
1950 buf = ALLOCV_N(char, tmp, strlen(s) + 1);
1951 b = buf;
1952
1953 skip_ws(&s);
1954 if (!read_comp(&s, strict, num, &b)) {
1955 ret = 0;
1956 }
1957 else {
1958 skip_ws(&s);
1959
1960 if (strict)
1961 if (*s != '\0')
1962 ret = 0;
1963 }
1964 ALLOCV_END(tmp);
1965
1966 return ret;
1967}
1968
1969static VALUE
1970string_to_c_strict(VALUE self, int raise)
1971{
1972 char *s;
1973 VALUE num;
1974
1975 rb_must_asciicompat(self);
1976
1977 s = RSTRING_PTR(self);
1978
1979 if (!s || memchr(s, '\0', RSTRING_LEN(self))) {
1980 if (!raise) return Qnil;
1981 rb_raise(rb_eArgError, "string contains null byte");
1982 }
1983
1984 if (s && s[RSTRING_LEN(self)]) {
1985 rb_str_modify(self);
1986 s = RSTRING_PTR(self);
1987 s[RSTRING_LEN(self)] = '\0';
1988 }
1989
1990 if (!s)
1991 s = (char *)"";
1992
1993 if (!parse_comp(s, 1, &num)) {
1994 if (!raise) return Qnil;
1995 rb_raise(rb_eArgError, "invalid value for convert(): %+"PRIsVALUE,
1996 self);
1997 }
1998
1999 return num;
2000}
2001
2002/*
2003 * call-seq:
2004 * str.to_c -> complex
2005 *
2006 * Returns a complex which denotes the string form. The parser
2007 * ignores leading whitespaces and trailing garbage. Any digit
2008 * sequences can be separated by an underscore. Returns zero for null
2009 * or garbage string.
2010 *
2011 * '9'.to_c #=> (9+0i)
2012 * '2.5'.to_c #=> (2.5+0i)
2013 * '2.5/1'.to_c #=> ((5/2)+0i)
2014 * '-3/2'.to_c #=> ((-3/2)+0i)
2015 * '-i'.to_c #=> (0-1i)
2016 * '45i'.to_c #=> (0+45i)
2017 * '3-4i'.to_c #=> (3-4i)
2018 * '-4e2-4e-2i'.to_c #=> (-400.0-0.04i)
2019 * '-0.0-0.0i'.to_c #=> (-0.0-0.0i)
2020 * '1/2+3/4i'.to_c #=> ((1/2)+(3/4)*i)
2021 * 'ruby'.to_c #=> (0+0i)
2022 *
2023 * See Kernel.Complex.
2024 */
2025static VALUE
2026string_to_c(VALUE self)
2027{
2028 char *s;
2029 VALUE num;
2030
2031 rb_must_asciicompat(self);
2032
2033 s = RSTRING_PTR(self);
2034
2035 if (s && s[RSTRING_LEN(self)]) {
2036 rb_str_modify(self);
2037 s = RSTRING_PTR(self);
2038 s[RSTRING_LEN(self)] = '\0';
2039 }
2040
2041 if (!s)
2042 s = (char *)"";
2043
2044 (void)parse_comp(s, 0, &num);
2045
2046 return num;
2047}
2048
2049static VALUE
2050to_complex(VALUE val)
2051{
2052 return rb_convert_type(val, T_COMPLEX, "Complex", "to_c");
2053}
2054
2055static VALUE
2056nucomp_convert(VALUE klass, VALUE a1, VALUE a2, int raise)
2057{
2058 if (NIL_P(a1) || NIL_P(a2)) {
2059 if (!raise) return Qnil;
2060 rb_raise(rb_eTypeError, "can't convert nil into Complex");
2061 }
2062
2063 if (RB_TYPE_P(a1, T_STRING)) {
2064 a1 = string_to_c_strict(a1, raise);
2065 if (NIL_P(a1)) return Qnil;
2066 }
2067
2068 if (RB_TYPE_P(a2, T_STRING)) {
2069 a2 = string_to_c_strict(a2, raise);
2070 if (NIL_P(a2)) return Qnil;
2071 }
2072
2073 if (RB_TYPE_P(a1, T_COMPLEX)) {
2074 {
2075 get_dat1(a1);
2076
2077 if (k_exact_zero_p(dat->imag))
2078 a1 = dat->real;
2079 }
2080 }
2081
2082 if (RB_TYPE_P(a2, T_COMPLEX)) {
2083 {
2084 get_dat1(a2);
2085
2086 if (k_exact_zero_p(dat->imag))
2087 a2 = dat->real;
2088 }
2089 }
2090
2091 if (RB_TYPE_P(a1, T_COMPLEX)) {
2092 if (a2 == Qundef || (k_exact_zero_p(a2)))
2093 return a1;
2094 }
2095
2096 if (a2 == Qundef) {
2097 if (k_numeric_p(a1) && !f_real_p(a1))
2098 return a1;
2099 /* should raise exception for consistency */
2100 if (!k_numeric_p(a1)) {
2101 if (!raise)
2102 return rb_protect(to_complex, a1, NULL);
2103 return to_complex(a1);
2104 }
2105 }
2106 else {
2107 if ((k_numeric_p(a1) && k_numeric_p(a2)) &&
2108 (!f_real_p(a1) || !f_real_p(a2)))
2109 return f_add(a1,
2110 f_mul(a2,
2111 f_complex_new_bang2(rb_cComplex, ZERO, ONE)));
2112 }
2113
2114 {
2115 int argc;
2116 VALUE argv2[2];
2117 argv2[0] = a1;
2118 if (a2 == Qundef) {
2119 argv2[1] = Qnil;
2120 argc = 1;
2121 }
2122 else {
2123 if (!raise && !RB_INTEGER_TYPE_P(a2) && !RB_FLOAT_TYPE_P(a2) && !RB_TYPE_P(a2, T_RATIONAL))
2124 return Qnil;
2125 argv2[1] = a2;
2126 argc = 2;
2127 }
2128 return nucomp_s_new(argc, argv2, klass);
2129 }
2130}
2131
2132static VALUE
2133nucomp_s_convert(int argc, VALUE *argv, VALUE klass)
2134{
2135 VALUE a1, a2;
2136
2137 if (rb_scan_args(argc, argv, "11", &a1, &a2) == 1) {
2138 a2 = Qundef;
2139 }
2140
2141 return nucomp_convert(klass, a1, a2, TRUE);
2142}
2143
2144/* --- */
2145
2146/*
2147 * call-seq:
2148 * num.real -> self
2149 *
2150 * Returns self.
2151 */
2152static VALUE
2153numeric_real(VALUE self)
2154{
2155 return self;
2156}
2157
2158/*
2159 * call-seq:
2160 * num.imag -> 0
2161 * num.imaginary -> 0
2162 *
2163 * Returns zero.
2164 */
2165static VALUE
2166numeric_imag(VALUE self)
2167{
2168 return INT2FIX(0);
2169}
2170
2171/*
2172 * call-seq:
2173 * num.abs2 -> real
2174 *
2175 * Returns square of self.
2176 */
2177static VALUE
2178numeric_abs2(VALUE self)
2179{
2180 return f_mul(self, self);
2181}
2182
2183/*
2184 * call-seq:
2185 * num.arg -> 0 or float
2186 * num.angle -> 0 or float
2187 * num.phase -> 0 or float
2188 *
2189 * Returns 0 if the value is positive, pi otherwise.
2190 */
2191static VALUE
2192numeric_arg(VALUE self)
2193{
2194 if (f_positive_p(self))
2195 return INT2FIX(0);
2196 return DBL2NUM(M_PI);
2197}
2198
2199/*
2200 * call-seq:
2201 * num.rect -> array
2202 * num.rectangular -> array
2203 *
2204 * Returns an array; [num, 0].
2205 */
2206static VALUE
2207numeric_rect(VALUE self)
2208{
2209 return rb_assoc_new(self, INT2FIX(0));
2210}
2211
2212static VALUE float_arg(VALUE self);
2213
2214/*
2215 * call-seq:
2216 * num.polar -> array
2217 *
2218 * Returns an array; [num.abs, num.arg].
2219 */
2220static VALUE
2221numeric_polar(VALUE self)
2222{
2223 VALUE abs, arg;
2224
2225 if (RB_INTEGER_TYPE_P(self)) {
2226 abs = rb_int_abs(self);
2227 arg = numeric_arg(self);
2228 }
2229 else if (RB_FLOAT_TYPE_P(self)) {
2230 abs = rb_float_abs(self);
2231 arg = float_arg(self);
2232 }
2233 else if (RB_TYPE_P(self, T_RATIONAL)) {
2234 abs = rb_rational_abs(self);
2235 arg = numeric_arg(self);
2236 }
2237 else {
2238 abs = f_abs(self);
2239 arg = f_arg(self);
2240 }
2241 return rb_assoc_new(abs, arg);
2242}
2243
2244/*
2245 * call-seq:
2246 * num.conj -> self
2247 * num.conjugate -> self
2248 *
2249 * Returns self.
2250 */
2251static VALUE
2252numeric_conj(VALUE self)
2253{
2254 return self;
2255}
2256
2257/*
2258 * call-seq:
2259 * flo.arg -> 0 or float
2260 * flo.angle -> 0 or float
2261 * flo.phase -> 0 or float
2262 *
2263 * Returns 0 if the value is positive, pi otherwise.
2264 */
2265static VALUE
2266float_arg(VALUE self)
2267{
2268 if (isnan(RFLOAT_VALUE(self)))
2269 return self;
2270 if (f_tpositive_p(self))
2271 return INT2FIX(0);
2272 return rb_const_get(rb_mMath, id_PI);
2273}
2274
2275/*
2276 * A complex number can be represented as a paired real number with
2277 * imaginary unit; a+bi. Where a is real part, b is imaginary part
2278 * and i is imaginary unit. Real a equals complex a+0i
2279 * mathematically.
2280 *
2281 * Complex object can be created as literal, and also by using
2282 * Kernel#Complex, Complex::rect, Complex::polar or to_c method.
2283 *
2284 * 2+1i #=> (2+1i)
2285 * Complex(1) #=> (1+0i)
2286 * Complex(2, 3) #=> (2+3i)
2287 * Complex.polar(2, 3) #=> (-1.9799849932008908+0.2822400161197344i)
2288 * 3.to_c #=> (3+0i)
2289 *
2290 * You can also create complex object from floating-point numbers or
2291 * strings.
2292 *
2293 * Complex(0.3) #=> (0.3+0i)
2294 * Complex('0.3-0.5i') #=> (0.3-0.5i)
2295 * Complex('2/3+3/4i') #=> ((2/3)+(3/4)*i)
2296 * Complex('1@2') #=> (-0.4161468365471424+0.9092974268256817i)
2297 *
2298 * 0.3.to_c #=> (0.3+0i)
2299 * '0.3-0.5i'.to_c #=> (0.3-0.5i)
2300 * '2/3+3/4i'.to_c #=> ((2/3)+(3/4)*i)
2301 * '1@2'.to_c #=> (-0.4161468365471424+0.9092974268256817i)
2302 *
2303 * A complex object is either an exact or an inexact number.
2304 *
2305 * Complex(1, 1) / 2 #=> ((1/2)+(1/2)*i)
2306 * Complex(1, 1) / 2.0 #=> (0.5+0.5i)
2307 */
2308void
2310{
2311 VALUE compat;
2312#undef rb_intern
2313#define rb_intern(str) rb_intern_const(str)
2314
2315 id_abs = rb_intern("abs");
2316 id_arg = rb_intern("arg");
2317 id_denominator = rb_intern("denominator");
2318 id_numerator = rb_intern("numerator");
2319 id_real_p = rb_intern("real?");
2320 id_i_real = rb_intern("@real");
2321 id_i_imag = rb_intern("@image"); /* @image, not @imag */
2322 id_finite_p = rb_intern("finite?");
2323 id_infinite_p = rb_intern("infinite?");
2324 id_rationalize = rb_intern("rationalize");
2325 id_PI = rb_intern("PI");
2326
2328
2329 rb_define_alloc_func(rb_cComplex, nucomp_s_alloc);
2330 rb_undef_method(CLASS_OF(rb_cComplex), "allocate");
2331
2333
2334 rb_define_singleton_method(rb_cComplex, "rectangular", nucomp_s_new, -1);
2335 rb_define_singleton_method(rb_cComplex, "rect", nucomp_s_new, -1);
2336 rb_define_singleton_method(rb_cComplex, "polar", nucomp_s_polar, -1);
2337
2338 rb_define_global_function("Complex", nucomp_f_complex, -1);
2339
2343 rb_undef_method(rb_cComplex, "divmod");
2344 rb_undef_method(rb_cComplex, "floor");
2346 rb_undef_method(rb_cComplex, "modulo");
2347 rb_undef_method(rb_cComplex, "remainder");
2348 rb_undef_method(rb_cComplex, "round");
2350 rb_undef_method(rb_cComplex, "truncate");
2352
2356
2363 rb_define_method(rb_cComplex, "fdiv", nucomp_fdiv, 1);
2365
2366 rb_define_method(rb_cComplex, "==", nucomp_eqeq_p, 1);
2367 rb_define_method(rb_cComplex, "<=>", nucomp_cmp, 1);
2368 rb_define_method(rb_cComplex, "coerce", nucomp_coerce, 1);
2369
2372 rb_define_method(rb_cComplex, "abs2", nucomp_abs2, 0);
2376 rb_define_method(rb_cComplex, "rectangular", nucomp_rect, 0);
2377 rb_define_method(rb_cComplex, "rect", nucomp_rect, 0);
2378 rb_define_method(rb_cComplex, "polar", nucomp_polar, 0);
2381
2382 rb_define_method(rb_cComplex, "real?", nucomp_false, 0);
2383
2384 rb_define_method(rb_cComplex, "numerator", nucomp_numerator, 0);
2385 rb_define_method(rb_cComplex, "denominator", nucomp_denominator, 0);
2386
2387 rb_define_method(rb_cComplex, "hash", nucomp_hash, 0);
2388 rb_define_method(rb_cComplex, "eql?", nucomp_eql_p, 1);
2389
2390 rb_define_method(rb_cComplex, "to_s", nucomp_to_s, 0);
2391 rb_define_method(rb_cComplex, "inspect", nucomp_inspect, 0);
2392
2393 rb_undef_method(rb_cComplex, "positive?");
2394 rb_undef_method(rb_cComplex, "negative?");
2395
2396 rb_define_method(rb_cComplex, "finite?", rb_complex_finite_p, 0);
2397 rb_define_method(rb_cComplex, "infinite?", rb_complex_infinite_p, 0);
2398
2399 rb_define_private_method(rb_cComplex, "marshal_dump", nucomp_marshal_dump, 0);
2400 /* :nodoc: */
2401 compat = rb_define_class_under(rb_cComplex, "compatible", rb_cObject);
2402 rb_define_private_method(compat, "marshal_load", nucomp_marshal_load, 1);
2403 rb_marshal_define_compat(rb_cComplex, compat, nucomp_dumper, nucomp_loader);
2404
2405 /* --- */
2406
2407 rb_define_method(rb_cComplex, "to_i", nucomp_to_i, 0);
2408 rb_define_method(rb_cComplex, "to_f", nucomp_to_f, 0);
2409 rb_define_method(rb_cComplex, "to_r", nucomp_to_r, 0);
2410 rb_define_method(rb_cComplex, "rationalize", nucomp_rationalize, -1);
2411 rb_define_method(rb_cComplex, "to_c", nucomp_to_c, 0);
2412 rb_define_method(rb_cNilClass, "to_c", nilclass_to_c, 0);
2413 rb_define_method(rb_cNumeric, "to_c", numeric_to_c, 0);
2414
2415 rb_define_method(rb_cString, "to_c", string_to_c, 0);
2416
2417 rb_define_private_method(CLASS_OF(rb_cComplex), "convert", nucomp_s_convert, -1);
2418
2419 /* --- */
2420
2421 rb_define_method(rb_cNumeric, "real", numeric_real, 0);
2422 rb_define_method(rb_cNumeric, "imaginary", numeric_imag, 0);
2423 rb_define_method(rb_cNumeric, "imag", numeric_imag, 0);
2424 rb_define_method(rb_cNumeric, "abs2", numeric_abs2, 0);
2425 rb_define_method(rb_cNumeric, "arg", numeric_arg, 0);
2426 rb_define_method(rb_cNumeric, "angle", numeric_arg, 0);
2427 rb_define_method(rb_cNumeric, "phase", numeric_arg, 0);
2428 rb_define_method(rb_cNumeric, "rectangular", numeric_rect, 0);
2429 rb_define_method(rb_cNumeric, "rect", numeric_rect, 0);
2430 rb_define_method(rb_cNumeric, "polar", numeric_polar, 0);
2431 rb_define_method(rb_cNumeric, "conjugate", numeric_conj, 0);
2432 rb_define_method(rb_cNumeric, "conj", numeric_conj, 0);
2433
2434 rb_define_method(rb_cFloat, "arg", float_arg, 0);
2435 rb_define_method(rb_cFloat, "angle", float_arg, 0);
2436 rb_define_method(rb_cFloat, "phase", float_arg, 0);
2437
2438 /*
2439 * The imaginary unit.
2440 */
2442 f_complex_new_bang2(rb_cComplex, ZERO, ONE));
2443
2444#if !USE_FLONUM
2446#endif
2447
2448 rb_provide("complex.so"); /* for backward compatibility */
2449}
#define id_quo
Definition: complex.c:45
#define id_to_i
Definition: complex.c:40
#define k_exact_zero_p(x)
Definition: complex.c:380
VALUE rb_complex_real(VALUE self)
Definition: complex.c:726
#define f_boolcast(x)
Definition: complex.c:48
#define id_fdiv
Definition: complex.c:46
VALUE rb_complex_uminus(VALUE self)
Definition: complex.c:758
#define ONE
Definition: complex.c:21
VALUE rb_complex_minus(VALUE self, VALUE other)
Definition: complex.c:812
VALUE rb_cComplex
Definition: complex.c:33
#define f_positive_p(x)
Definition: complex.c:314
#define get_dat2(x, y)
Definition: complex.c:385
VALUE rb_Complex(VALUE x, VALUE y)
Definition: complex.c:1545
#define id_expt
Definition: complex.c:43
VALUE rb_complex_new_polar(VALUE x, VALUE y)
Definition: complex.c:1533
void Init_Complex(void)
Definition: complex.c:2309
VALUE rb_complex_div(VALUE self, VALUE other)
Definition: complex.c:948
VALUE rb_complex_plus(VALUE self, VALUE other)
Definition: complex.c:778
VALUE rb_complex_raw(VALUE x, VALUE y)
Definition: complex.c:1521
VALUE rb_complex_pow(VALUE self, VALUE other)
Definition: complex.c:985
VALUE rb_complex_arg(VALUE self)
Definition: complex.c:1208
VALUE rb_complex_abs(VALUE self)
Definition: complex.c:1161
VALUE rb_dbl_complex_new(double real, double imag)
Creates a Complex object.
Definition: complex.c:1561
#define nucomp_quo
Definition: complex.c:953
#define TWO
Definition: complex.c:22
VALUE rb_dbl_complex_new_polar_pi(double abs, double ang)
Definition: complex.c:667
#define rb_intern(str)
#define imp1(n)
Definition: complex.c:572
#define id_to_f
Definition: complex.c:44
VALUE rb_flo_is_finite_p(VALUE num)
Definition: numeric.c:1770
VALUE rb_complex_imag(VALUE self)
Definition: complex.c:743
#define ZERO
Definition: complex.c:20
#define get_dat1(x)
Definition: complex.c:382
#define id_negate
Definition: complex.c:42
VALUE rb_flo_is_infinite_p(VALUE num)
Definition: numeric.c:1750
VALUE rb_complex_new(VALUE x, VALUE y)
Definition: complex.c:1527
VALUE rb_complex_mul(VALUE self, VALUE other)
Definition: complex.c:872
VALUE rb_complex_conjugate(VALUE self)
Definition: complex.c:1254
#define fun1(n)
Definition: complex.c:50
#define fun2(n)
Definition: complex.c:57
#define canonicalization
Definition: complex.c:430
#define RFLOAT_0
Definition: complex.c:24
VALUE rb_complex_polar(VALUE x, VALUE y)
Definition: complex.c:1539
#define f_add(x, y)
Definition: date_core.c:34
#define f_negate(x)
Definition: date_core.c:33
#define f_mul(x, y)
Definition: date_core.c:36
#define f_sub(x, y)
Definition: date_core.c:35
#define f_to_i(x)
Definition: date_core.c:48
#define f_div(x, y)
Definition: date_core.c:37
#define f_to_r(x)
Definition: date_core.c:49
#define f_expt(x, y)
Definition: date_core.c:42
#define f_abs(x)
Definition: date_core.c:32
#define f_quo(x, y)
Definition: date_core.c:38
#define issign(c)
Definition: date_parse.c:60
#define f_gt_p(x, y)
Definition: date_parse.c:27
#define str2num(s)
Definition: date_parse.c:48
#define rb_cmpint(cmp, a, b)
VALUE rb_define_class(const char *, VALUE)
Defines a top-level class.
Definition: class.c:662
VALUE rb_define_class_under(VALUE, const char *, VALUE)
Defines a class under the namespace of outer.
Definition: class.c:711
void rb_undef_method(VALUE, const char *)
Definition: class.c:1593
void rb_undef_methods_from(VALUE klass, VALUE super)
Definition: class.c:1607
VALUE rb_cNilClass
NilClass class.
Definition: ruby.h:2038
VALUE rb_cRational
Definition: ruby.h:2043
VALUE rb_cObject
Object class.
Definition: ruby.h:2012
VALUE rb_cInteger
Definition: ruby.h:2033
VALUE rb_cNumeric
Definition: ruby.h:2039
VALUE rb_cString
Definition: ruby.h:2046
VALUE rb_mComparable
Definition: compar.c:16
VALUE rb_cFloat
Definition: ruby.h:2030
VALUE rb_mMath
Definition: ruby.h:2006
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2671
VALUE rb_eRangeError
Definition: error.c:928
VALUE rb_eTypeError
Definition: error.c:924
VALUE rb_protect(VALUE(*)(VALUE), VALUE, int *)
Protects a function call from potential global escapes from the function.
Definition: eval.c:1072
void rb_warn(const char *fmt,...)
Definition: error.c:315
VALUE rb_eArgError
Definition: error.c:925
VALUE rb_convert_type(VALUE, int, const char *, const char *)
Converts an object into another type.
Definition: object.c:2900
int rb_opts_exception_p(VALUE opts, int default_value)
Definition: object.c:3125
double rb_str_to_dbl(VALUE, int)
Parses a string representation of a floating point number.
Definition: object.c:3371
VALUE rb_obj_class(VALUE)
Equivalent to Object#class in Ruby.
Definition: object.c:217
VALUE rb_inspect(VALUE)
Convenient wrapper of Object::inspect.
Definition: object.c:551
VALUE rb_equal(VALUE, VALUE)
Same as Object#===, case equality.
Definition: object.c:124
VALUE rb_obj_is_kind_of(VALUE, VALUE)
Determines if obj is a kind of c.
Definition: object.c:692
double rb_cstr_to_dbl(const char *, int)
Parses a string representation of a floating point number.
Definition: object.c:3319
VALUE rb_String(VALUE)
Equivalent to Kernel#String in Ruby.
Definition: object.c:3652
#define id_numerator
Definition: rational.c:1983
#define f_reciprocal(x)
Definition: rational.c:1630
#define id_denominator
Definition: rational.c:1986
#define f_denominator(x)
Definition: rational.c:1987
#define f_numerator(x)
Definition: rational.c:1984
#define RARRAY_LEN(a)
void * memchr(const void *, int, size_t)
VALUE rb_math_log(int argc, const VALUE *argv)
Definition: math.c:459
#define T_COMPLEX
#define NULL
#define rb_funcallv(recv, mid, argc, argv)
#define NUM2DBL(x)
void rb_provide(const char *)
Definition: load.c:607
VALUE rb_hash(VALUE)
Definition: hash.c:129
#define RSTRING_LEN(str)
VALUE rb_rational_cmp(VALUE self, VALUE other)
Definition: rational.c:1097
#define NEWOBJ_OF(obj, type, klass, flags)
#define RTEST(v)
#define ALLOCV_END(v)
VALUE rb_rational_uminus(VALUE self)
Definition: rational.c:624
VALUE rb_const_get(VALUE, ID)
Definition: variable.c:2391
enum ruby_tag_type st
double cosh(double)
Definition: math.c:228
void rb_copy_generic_ivar(VALUE, VALUE)
Definition: variable.c:1447
void rb_must_asciicompat(VALUE)
Definition: string.c:2166
size_t strlen(const char *)
void rb_define_private_method(VALUE, const char *, VALUE(*)(), int)
#define T_STRING
VALUE rb_assoc_new(VALUE, VALUE)
Definition: array.c:896
int abs(int)
VALUE rb_num_pow(VALUE x, VALUE y)
Definition: numeric.c:4123
void rb_define_global_function(const char *, VALUE(*)(), int)
#define LONG2FIX(i)
#define Qundef
VALUE rb_str_concat(VALUE, VALUE)
Definition: string.c:3065
VALUE rb_num_coerce_bin(VALUE, VALUE, ID)
Definition: numeric.c:446
#define rb_str_cat2
VALUE rb_int_abs(VALUE num)
Definition: numeric.c:4862
VALUE rb_ivar_get(VALUE, ID)
Definition: variable.c:1070
const VALUE VALUE obj
VALUE rb_rational_plus(VALUE self, VALUE other)
Definition: rational.c:737
#define RSTRING_PTR(str)
void rb_gc_register_mark_object(VALUE)
Definition: gc.c:7079
#define T_BIGNUM
st_index_t rb_memhash(const void *ptr, long len)
Definition: random.c:1444
#define NIL_P(v)
#define DBL2NUM(dbl)
VALUE rb_float_numerator(VALUE x)
Definition: rational.c:2093
#define signbit(__x)
char * strpbrk(const char *, const char *)
const char size_t n
double sinh(double)
Definition: math.c:256
#define rb_complex_new2(x, y)
unsigned long VALUE
VALUE rb_math_atan2(VALUE, VALUE)
VALUE rb_int_uminus(VALUE num)
Definition: numeric.c:3484
VALUE rb_float_mul(VALUE x, VALUE y)
Definition: numeric.c:1072
void rb_str_modify(VALUE)
Definition: string.c:2114
double modf(double, double *)
VALUE rb_float_plus(VALUE x, VALUE y)
Definition: numeric.c:1024
VALUE rb_cstr_to_inum(const char *, int, int)
Definition: bignum.c:4012
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
#define RB_FLOAT_TYPE_P(obj)
#define isnan(__x)
double cos(double)
VALUE rb_float_denominator(VALUE x)
Definition: rational.c:2116
#define RGENGC_WB_PROTECTED_COMPLEX
VALUE rb_float_abs(VALUE flt)
Definition: numeric.c:1698
#define T_RATIONAL
VALUE rb_rational_abs(VALUE self)
Definition: rational.c:1255
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:2891
VALUE rb_float_uminus(VALUE num)
Definition: numeric.c:1011
void rb_define_singleton_method(VALUE, const char *, VALUE(*)(), int)
VALUE rb_str_to_inum(VALUE, int, int)
Definition: bignum.c:4268
#define PRIsVALUE
#define rb_funcall(recv, mid, argc,...)
int VALUE v
#define rb_method_basic_definition_p(klass, mid)
VALUE rb_cstr_to_rat(const char *, int)
Definition: rational.c:2553
#define M_PI_2
#define rb_scan_args(argc, argvp, fmt,...)
#define rb_usascii_str_new2
VALUE rb_float_gt(VALUE x, VALUE y)
Definition: numeric.c:1503
int rb_num_negative_p(VALUE)
Definition: numeric.c:313
#define ALLOCV_N(type, v, n)
char * strchr(const char *, int)
Definition: strchr.c:8
#define RRATIONAL(obj)
#define RFLOAT_VALUE(v)
#define TRUE
#define Qtrue
#define INT_NEGATIVE_P(x)
VALUE rb_math_hypot(VALUE, VALUE)
struct rb_call_cache buf
VALUE rb_float_div(VALUE x, VALUE y)
Definition: numeric.c:1126
VALUE rb_lcm(VALUE x, VALUE y)
Definition: rational.c:1925
#define Qnil
#define Qfalse
#define T_ARRAY
#define OBJ_FREEZE_RAW(x)
#define SIGNED_VALUE
st_data_t st_index_t
#define rb_complex_new1(x)
#define FIXNUM_ZERO_P(num)
#define RB_TYPE_P(obj, type)
#define FL_WB_PROTECTED
#define INT2FIX(i)
const VALUE * argv
VALUE rb_ivar_set(VALUE, ID, VALUE)
Definition: variable.c:1300
#define FIXNUM_P(f)
#define CLASS_OF(v)
#define RCOMPLEX_SET_IMAG(cmp, i)
#define RCOMPLEX_SET_REAL(cmp, r)
#define Check_Type(v, t)
#define RB_INTEGER_TYPE_P(obj)
double sin(double)
#define assert
#define rb_check_arity
#define FLOAT_ZERO_P(x)
unsigned long ID
#define M_PI
void rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE(*dumper)(VALUE), VALUE(*loader)(VALUE, VALUE))
Definition: marshal.c:134
double exp(double)
size_t st_index_t h
#define RUBY_FUNC_EXPORTED
#define FIX2LONG(x)
#define NUM2LONG(x)
void rb_define_method(VALUE, const char *, VALUE(*)(), int)
#define RARRAY_AREF(a, i)
#define ST2FIX(h)
VALUE rb_rational_canonicalize(VALUE x)
Definition: rational.c:2046
VALUE rb_rational_mul(VALUE self, VALUE other)
Definition: rational.c:874
VALUE rb_int_plus(VALUE x, VALUE y)
Definition: numeric.c:3615
VALUE rb_int_gt(VALUE x, VALUE y)
Definition: numeric.c:4257
VALUE rb_numeric_quo(VALUE x, VALUE y)
Definition: rational.c:2026
VALUE rb_int_mul(VALUE x, VALUE y)
Definition: numeric.c:3704
#define LIKELY(x)
#define f