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