Ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e0ba6b95ab71a441357ed5484e33498)
complex.c
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/internal/config.h"
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#include "id.h"
19#include "internal.h"
20#include "internal/array.h"
21#include "internal/class.h"
22#include "internal/complex.h"
23#include "internal/math.h"
24#include "internal/numeric.h"
25#include "internal/object.h"
26#include "internal/rational.h"
27#include "ruby_assert.h"
28
29#define ZERO INT2FIX(0)
30#define ONE INT2FIX(1)
31#define TWO INT2FIX(2)
32#if USE_FLONUM
33#define RFLOAT_0 DBL2NUM(0)
34#else
35static VALUE RFLOAT_0;
36#endif
37
39
40static ID id_abs, id_arg,
41 id_denominator, id_numerator,
42 id_real_p, id_i_real, id_i_imag,
43 id_finite_p, id_infinite_p, id_rationalize,
44 id_PI;
45#define id_to_i idTo_i
46#define id_to_r idTo_r
47#define id_negate idUMinus
48#define id_expt idPow
49#define id_to_f idTo_f
50#define id_quo idQuo
51#define id_fdiv idFdiv
52
53#define fun1(n) \
54inline static VALUE \
55f_##n(VALUE x)\
56{\
57 return rb_funcall(x, id_##n, 0);\
58}
59
60#define fun2(n) \
61inline static VALUE \
62f_##n(VALUE x, VALUE y)\
63{\
64 return rb_funcall(x, id_##n, 1, y);\
65}
66
67#define PRESERVE_SIGNEDZERO
68
69inline static VALUE
70f_add(VALUE x, VALUE y)
71{
72 if (RB_INTEGER_TYPE_P(x) &&
74 if (FIXNUM_ZERO_P(x))
75 return y;
76 if (FIXNUM_ZERO_P(y))
77 return x;
78 return rb_int_plus(x, y);
79 }
80 else if (RB_FLOAT_TYPE_P(x) &&
81 LIKELY(rb_method_basic_definition_p(rb_cFloat, idPLUS))) {
82 if (FIXNUM_ZERO_P(y))
83 return x;
84 return rb_float_plus(x, y);
85 }
86 else if (RB_TYPE_P(x, T_RATIONAL) &&
88 if (FIXNUM_ZERO_P(y))
89 return x;
90 return rb_rational_plus(x, y);
91 }
92
93 return rb_funcall(x, '+', 1, y);
94}
95
96inline static VALUE
97f_div(VALUE x, VALUE y)
98{
99 if (FIXNUM_P(y) && FIX2LONG(y) == 1)
100 return x;
101 return rb_funcall(x, '/', 1, y);
102}
103
104inline static int
105f_gt_p(VALUE x, VALUE y)
106{
107 if (RB_INTEGER_TYPE_P(x)) {
108 if (FIXNUM_P(x) && FIXNUM_P(y))
109 return (SIGNED_VALUE)x > (SIGNED_VALUE)y;
110 return RTEST(rb_int_gt(x, y));
111 }
112 else if (RB_FLOAT_TYPE_P(x))
113 return RTEST(rb_float_gt(x, y));
114 else if (RB_TYPE_P(x, T_RATIONAL)) {
115 int const cmp = rb_cmpint(rb_rational_cmp(x, y), x, y);
116 return cmp > 0;
117 }
118 return RTEST(rb_funcall(x, '>', 1, y));
119}
120
121inline static VALUE
122f_mul(VALUE x, VALUE y)
123{
124 if (RB_INTEGER_TYPE_P(x) &&
125 LIKELY(rb_method_basic_definition_p(rb_cInteger, idMULT))) {
126 if (FIXNUM_ZERO_P(y))
127 return ZERO;
128 if (FIXNUM_ZERO_P(x) && RB_INTEGER_TYPE_P(y))
129 return ZERO;
130 if (x == ONE) return y;
131 if (y == ONE) return x;
132 return rb_int_mul(x, y);
133 }
134 else if (RB_FLOAT_TYPE_P(x) &&
135 LIKELY(rb_method_basic_definition_p(rb_cFloat, idMULT))) {
136 if (y == ONE) return x;
137 return rb_float_mul(x, y);
138 }
139 else if (RB_TYPE_P(x, T_RATIONAL) &&
141 if (y == ONE) return x;
142 return rb_rational_mul(x, y);
143 }
144 else if (LIKELY(rb_method_basic_definition_p(CLASS_OF(x), idMULT))) {
145 if (y == ONE) return x;
146 }
147 return rb_funcall(x, '*', 1, y);
148}
149
150inline static VALUE
151f_sub(VALUE x, VALUE y)
152{
153 if (FIXNUM_ZERO_P(y) &&
154 LIKELY(rb_method_basic_definition_p(CLASS_OF(x), idMINUS))) {
155 return x;
156 }
157 return rb_funcall(x, '-', 1, y);
158}
159
160inline static VALUE
161f_abs(VALUE x)
162{
163 if (RB_INTEGER_TYPE_P(x)) {
164 return rb_int_abs(x);
165 }
166 else if (RB_FLOAT_TYPE_P(x)) {
167 return rb_float_abs(x);
168 }
169 else if (RB_TYPE_P(x, T_RATIONAL)) {
170 return rb_rational_abs(x);
171 }
172 else if (RB_TYPE_P(x, T_COMPLEX)) {
173 return rb_complex_abs(x);
174 }
175 return rb_funcall(x, id_abs, 0);
176}
177
178static VALUE numeric_arg(VALUE self);
179static VALUE float_arg(VALUE self);
180
181inline static VALUE
182f_arg(VALUE x)
183{
184 if (RB_INTEGER_TYPE_P(x)) {
185 return numeric_arg(x);
186 }
187 else if (RB_FLOAT_TYPE_P(x)) {
188 return float_arg(x);
189 }
190 else if (RB_TYPE_P(x, T_RATIONAL)) {
191 return numeric_arg(x);
192 }
193 else if (RB_TYPE_P(x, T_COMPLEX)) {
194 return rb_complex_arg(x);
195 }
196 return rb_funcall(x, id_arg, 0);
197}
198
199inline static VALUE
200f_numerator(VALUE x)
201{
202 if (RB_TYPE_P(x, T_RATIONAL)) {
203 return RRATIONAL(x)->num;
204 }
205 if (RB_FLOAT_TYPE_P(x)) {
206 return rb_float_numerator(x);
207 }
208 return x;
209}
210
211inline static VALUE
212f_denominator(VALUE x)
213{
214 if (RB_TYPE_P(x, T_RATIONAL)) {
215 return RRATIONAL(x)->den;
216 }
217 if (RB_FLOAT_TYPE_P(x)) {
218 return rb_float_denominator(x);
219 }
220 return INT2FIX(1);
221}
222
223inline static VALUE
224f_negate(VALUE x)
225{
226 if (RB_INTEGER_TYPE_P(x)) {
227 return rb_int_uminus(x);
228 }
229 else if (RB_FLOAT_TYPE_P(x)) {
230 return rb_float_uminus(x);
231 }
232 else if (RB_TYPE_P(x, T_RATIONAL)) {
233 return rb_rational_uminus(x);
234 }
235 else if (RB_TYPE_P(x, T_COMPLEX)) {
236 return rb_complex_uminus(x);
237 }
238 return rb_funcall(x, id_negate, 0);
239}
240
241static bool nucomp_real_p(VALUE self);
242
243static inline bool
244f_real_p(VALUE x)
245{
246 if (RB_INTEGER_TYPE_P(x)) {
247 return true;
248 }
249 else if (RB_FLOAT_TYPE_P(x)) {
250 return true;
251 }
252 else if (RB_TYPE_P(x, T_RATIONAL)) {
253 return true;
254 }
255 else if (RB_TYPE_P(x, T_COMPLEX)) {
256 return nucomp_real_p(x);
257 }
258 return rb_funcall(x, id_real_p, 0);
259}
260
261inline static VALUE
262f_to_i(VALUE x)
263{
264 if (RB_TYPE_P(x, T_STRING))
265 return rb_str_to_inum(x, 10, 0);
266 return rb_funcall(x, id_to_i, 0);
267}
268
269inline static VALUE
270f_to_f(VALUE x)
271{
272 if (RB_TYPE_P(x, T_STRING))
273 return DBL2NUM(rb_str_to_dbl(x, 0));
274 return rb_funcall(x, id_to_f, 0);
275}
276
277fun1(to_r)
278
279inline static int
280f_eqeq_p(VALUE x, VALUE y)
281{
282 if (FIXNUM_P(x) && FIXNUM_P(y))
283 return x == y;
284 else if (RB_FLOAT_TYPE_P(x) || RB_FLOAT_TYPE_P(y))
285 return NUM2DBL(x) == NUM2DBL(y);
286 return (int)rb_equal(x, y);
287}
288
289fun2(expt)
290fun2(fdiv)
291
292static VALUE
293f_quo(VALUE x, VALUE y)
294{
295 if (RB_INTEGER_TYPE_P(x))
296 return rb_numeric_quo(x, y);
297 if (RB_FLOAT_TYPE_P(x))
298 return rb_float_div(x, y);
299 if (RB_TYPE_P(x, T_RATIONAL))
300 return rb_numeric_quo(x, y);
301
302 return rb_funcallv(x, id_quo, 1, &y);
303}
304
305inline static int
306f_negative_p(VALUE x)
307{
308 if (RB_INTEGER_TYPE_P(x))
309 return INT_NEGATIVE_P(x);
310 else if (RB_FLOAT_TYPE_P(x))
311 return RFLOAT_VALUE(x) < 0.0;
312 else if (RB_TYPE_P(x, T_RATIONAL))
313 return INT_NEGATIVE_P(RRATIONAL(x)->num);
314 return rb_num_negative_p(x);
315}
316
317#define f_positive_p(x) (!f_negative_p(x))
318
319inline static int
320f_zero_p(VALUE x)
321{
322 if (RB_FLOAT_TYPE_P(x)) {
323 return FLOAT_ZERO_P(x);
324 }
325 else if (RB_INTEGER_TYPE_P(x)) {
326 return FIXNUM_ZERO_P(x);
327 }
328 else if (RB_TYPE_P(x, T_RATIONAL)) {
329 const VALUE num = RRATIONAL(x)->num;
330 return FIXNUM_ZERO_P(num);
331 }
332 return (int)rb_equal(x, ZERO);
333}
334
335#define f_nonzero_p(x) (!f_zero_p(x))
336
337static inline bool
338always_finite_type_p(VALUE x)
339{
340 if (FIXNUM_P(x)) return true;
341 if (FLONUM_P(x)) return true; /* Infinity can't be a flonum */
342 return (RB_INTEGER_TYPE_P(x) || RB_TYPE_P(x, T_RATIONAL));
343}
344
345inline static int
346f_finite_p(VALUE x)
347{
348 if (always_finite_type_p(x)) {
349 return TRUE;
350 }
351 else if (RB_FLOAT_TYPE_P(x)) {
352 return isfinite(RFLOAT_VALUE(x));
353 }
354 return RTEST(rb_funcallv(x, id_finite_p, 0, 0));
355}
356
357inline static int
358f_infinite_p(VALUE x)
359{
360 if (always_finite_type_p(x)) {
361 return FALSE;
362 }
363 else if (RB_FLOAT_TYPE_P(x)) {
364 return isinf(RFLOAT_VALUE(x));
365 }
366 return RTEST(rb_funcallv(x, id_infinite_p, 0, 0));
367}
368
369inline static int
370f_kind_of_p(VALUE x, VALUE c)
371{
372 return (int)rb_obj_is_kind_of(x, c);
373}
374
375inline static int
376k_numeric_p(VALUE x)
377{
378 return f_kind_of_p(x, rb_cNumeric);
379}
380
381#define k_exact_p(x) (!RB_FLOAT_TYPE_P(x))
382
383#define k_exact_zero_p(x) (k_exact_p(x) && f_zero_p(x))
384
385#define get_dat1(x) \
386 struct RComplex *dat = RCOMPLEX(x)
387
388#define get_dat2(x,y) \
389 struct RComplex *adat = RCOMPLEX(x), *bdat = RCOMPLEX(y)
390
391inline static VALUE
392nucomp_s_new_internal(VALUE klass, VALUE real, VALUE imag)
393{
395
396 RCOMPLEX_SET_REAL(obj, real);
397 RCOMPLEX_SET_IMAG(obj, imag);
398 OBJ_FREEZE_RAW((VALUE)obj);
399
400 return (VALUE)obj;
401}
402
403static VALUE
404nucomp_s_alloc(VALUE klass)
405{
406 return nucomp_s_new_internal(klass, ZERO, ZERO);
407}
408
409inline static VALUE
410f_complex_new_bang1(VALUE klass, VALUE x)
411{
412 assert(!RB_TYPE_P(x, T_COMPLEX));
413 return nucomp_s_new_internal(klass, x, ZERO);
414}
415
416inline static VALUE
417f_complex_new_bang2(VALUE klass, VALUE x, VALUE y)
418{
419 assert(!RB_TYPE_P(x, T_COMPLEX));
420 assert(!RB_TYPE_P(y, T_COMPLEX));
421 return nucomp_s_new_internal(klass, x, y);
422}
423
424inline static void
425nucomp_real_check(VALUE num)
426{
427 if (!RB_INTEGER_TYPE_P(num) &&
428 !RB_FLOAT_TYPE_P(num) &&
429 !RB_TYPE_P(num, T_RATIONAL)) {
430 if (!k_numeric_p(num) || !f_real_p(num))
431 rb_raise(rb_eTypeError, "not a real");
432 }
433}
434
435inline static VALUE
436nucomp_s_canonicalize_internal(VALUE klass, VALUE real, VALUE imag)
437{
438 int complex_r, complex_i;
439 complex_r = RB_TYPE_P(real, T_COMPLEX);
440 complex_i = RB_TYPE_P(imag, T_COMPLEX);
441 if (!complex_r && !complex_i) {
442 return nucomp_s_new_internal(klass, real, imag);
443 }
444 else if (!complex_r) {
445 get_dat1(imag);
446
447 return nucomp_s_new_internal(klass,
448 f_sub(real, dat->imag),
449 f_add(ZERO, dat->real));
450 }
451 else if (!complex_i) {
452 get_dat1(real);
453
454 return nucomp_s_new_internal(klass,
455 dat->real,
456 f_add(dat->imag, imag));
457 }
458 else {
459 get_dat2(real, imag);
460
461 return nucomp_s_new_internal(klass,
462 f_sub(adat->real, bdat->imag),
463 f_add(adat->imag, bdat->real));
464 }
465}
466
467/*
468 * call-seq:
469 * Complex.rect(real[, imag]) -> complex
470 * Complex.rectangular(real[, imag]) -> complex
471 *
472 * Returns a complex object which denotes the given rectangular form.
473 *
474 * Complex.rectangular(1, 2) #=> (1+2i)
475 */
476static VALUE
477nucomp_s_new(int argc, VALUE *argv, VALUE klass)
478{
479 VALUE real, imag;
480
481 switch (rb_scan_args(argc, argv, "11", &real, &imag)) {
482 case 1:
483 nucomp_real_check(real);
484 imag = ZERO;
485 break;
486 default:
487 nucomp_real_check(real);
488 nucomp_real_check(imag);
489 break;
490 }
491
492 return nucomp_s_canonicalize_internal(klass, real, imag);
493}
494
495inline static VALUE
496f_complex_new2(VALUE klass, VALUE x, VALUE y)
497{
498 assert(!RB_TYPE_P(x, T_COMPLEX));
499 return nucomp_s_canonicalize_internal(klass, x, y);
500}
501
502static VALUE nucomp_convert(VALUE klass, VALUE a1, VALUE a2, int raise);
503static VALUE nucomp_s_convert(int argc, VALUE *argv, VALUE klass);
504
505/*
506 * call-seq:
507 * Complex(x[, y], exception: true) -> numeric or nil
508 *
509 * Returns x+i*y;
510 *
511 * Complex(1, 2) #=> (1+2i)
512 * Complex('1+2i') #=> (1+2i)
513 * Complex(nil) #=> TypeError
514 * Complex(1, nil) #=> TypeError
515 *
516 * Complex(1, nil, exception: false) #=> nil
517 * Complex('1+2', exception: false) #=> nil
518 *
519 * Syntax of string form:
520 *
521 * string form = extra spaces , complex , extra spaces ;
522 * complex = real part | [ sign ] , imaginary part
523 * | real part , sign , imaginary part
524 * | rational , "@" , rational ;
525 * real part = rational ;
526 * imaginary part = imaginary unit | unsigned rational , imaginary unit ;
527 * rational = [ sign ] , unsigned rational ;
528 * unsigned rational = numerator | numerator , "/" , denominator ;
529 * numerator = integer part | fractional part | integer part , fractional part ;
530 * denominator = digits ;
531 * integer part = digits ;
532 * fractional part = "." , digits , [ ( "e" | "E" ) , [ sign ] , digits ] ;
533 * imaginary unit = "i" | "I" | "j" | "J" ;
534 * sign = "-" | "+" ;
535 * digits = digit , { digit | "_" , digit };
536 * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
537 * extra spaces = ? \s* ? ;
538 *
539 * See String#to_c.
540 */
541static VALUE
542nucomp_f_complex(int argc, VALUE *argv, VALUE klass)
543{
544 VALUE a1, a2, opts = Qnil;
545 int raise = TRUE;
546
547 if (rb_scan_args(argc, argv, "11:", &a1, &a2, &opts) == 1) {
548 a2 = Qundef;
549 }
550 if (!NIL_P(opts)) {
551 raise = rb_opts_exception_p(opts, raise);
552 }
553 if (argc > 0 && CLASS_OF(a1) == rb_cComplex && a2 == Qundef) {
554 return a1;
555 }
556 return nucomp_convert(rb_cComplex, a1, a2, raise);
557}
558
559#define imp1(n) \
560inline static VALUE \
561m_##n##_bang(VALUE x)\
562{\
563 return rb_math_##n(x);\
564}
565
566imp1(cos)
567imp1(cosh)
568imp1(exp)
569
570static VALUE
571m_log_bang(VALUE x)
572{
573 return rb_math_log(1, &x);
574}
575
576imp1(sin)
577imp1(sinh)
578
579static VALUE
580m_cos(VALUE x)
581{
582 if (!RB_TYPE_P(x, T_COMPLEX))
583 return m_cos_bang(x);
584 {
585 get_dat1(x);
586 return f_complex_new2(rb_cComplex,
587 f_mul(m_cos_bang(dat->real),
588 m_cosh_bang(dat->imag)),
589 f_mul(f_negate(m_sin_bang(dat->real)),
590 m_sinh_bang(dat->imag)));
591 }
592}
593
594static VALUE
595m_sin(VALUE x)
596{
597 if (!RB_TYPE_P(x, T_COMPLEX))
598 return m_sin_bang(x);
599 {
600 get_dat1(x);
601 return f_complex_new2(rb_cComplex,
602 f_mul(m_sin_bang(dat->real),
603 m_cosh_bang(dat->imag)),
604 f_mul(m_cos_bang(dat->real),
605 m_sinh_bang(dat->imag)));
606 }
607}
608
609static VALUE
610f_complex_polar(VALUE klass, VALUE x, VALUE y)
611{
612 assert(!RB_TYPE_P(x, T_COMPLEX));
613 assert(!RB_TYPE_P(y, T_COMPLEX));
614 if (f_zero_p(x) || f_zero_p(y)) {
615 return nucomp_s_new_internal(klass, x, RFLOAT_0);
616 }
617 if (RB_FLOAT_TYPE_P(y)) {
618 const double arg = RFLOAT_VALUE(y);
619 if (arg == M_PI) {
620 x = f_negate(x);
621 y = RFLOAT_0;
622 }
623 else if (arg == M_PI_2) {
624 y = x;
625 x = RFLOAT_0;
626 }
627 else if (arg == M_PI_2+M_PI) {
628 y = f_negate(x);
629 x = RFLOAT_0;
630 }
631 else if (RB_FLOAT_TYPE_P(x)) {
632 const double abs = RFLOAT_VALUE(x);
633 const double real = abs * cos(arg), imag = abs * sin(arg);
634 x = DBL2NUM(real);
635 y = DBL2NUM(imag);
636 }
637 else {
638 const double ax = sin(arg), ay = cos(arg);
639 y = f_mul(x, DBL2NUM(ax));
640 x = f_mul(x, DBL2NUM(ay));
641 }
642 return nucomp_s_new_internal(klass, x, y);
643 }
644 return nucomp_s_canonicalize_internal(klass,
645 f_mul(x, m_cos(y)),
646 f_mul(x, m_sin(y)));
647}
648
649#ifdef HAVE___COSPI
650# define cospi(x) __cospi(x)
651#else
652# define cospi(x) cos((x) * M_PI)
653#endif
654#ifdef HAVE___SINPI
655# define sinpi(x) __sinpi(x)
656#else
657# define sinpi(x) sin((x) * M_PI)
658#endif
659/* returns a Complex or Float of ang*PI-rotated abs */
660VALUE
661rb_dbl_complex_new_polar_pi(double abs, double ang)
662{
663 double fi;
664 const double fr = modf(ang, &fi);
665 int pos = fr == +0.5;
666
667 if (pos || fr == -0.5) {
668 if ((modf(fi / 2.0, &fi) != fr) ^ pos) abs = -abs;
669 return rb_complex_new(RFLOAT_0, DBL2NUM(abs));
670 }
671 else if (fr == 0.0) {
672 if (modf(fi / 2.0, &fi) != 0.0) abs = -abs;
673 return DBL2NUM(abs);
674 }
675 else {
676 const double real = abs * cospi(ang), imag = abs * sinpi(ang);
677 return rb_complex_new(DBL2NUM(real), DBL2NUM(imag));
678 }
679}
680
681/*
682 * call-seq:
683 * Complex.polar(abs[, arg]) -> complex
684 *
685 * Returns a complex object which denotes the given polar form.
686 *
687 * Complex.polar(3, 0) #=> (3.0+0.0i)
688 * Complex.polar(3, Math::PI/2) #=> (1.836909530733566e-16+3.0i)
689 * Complex.polar(3, Math::PI) #=> (-3.0+3.673819061467132e-16i)
690 * Complex.polar(3, -Math::PI/2) #=> (1.836909530733566e-16-3.0i)
691 */
692static VALUE
693nucomp_s_polar(int argc, VALUE *argv, VALUE klass)
694{
695 VALUE abs, arg;
696
697 argc = rb_scan_args(argc, argv, "11", &abs, &arg);
698 nucomp_real_check(abs);
699 if (argc == 2) {
700 nucomp_real_check(arg);
701 }
702 else {
703 arg = ZERO;
704 }
705 if (RB_TYPE_P(abs, T_COMPLEX)) {
706 get_dat1(abs);
707 abs = dat->real;
708 }
709 if (RB_TYPE_P(arg, T_COMPLEX)) {
710 get_dat1(arg);
711 arg = dat->real;
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
778rb_complex_plus(VALUE self, VALUE other)
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
812rb_complex_minus(VALUE self, VALUE other)
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
872rb_complex_mul(VALUE self, VALUE other)
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) {
917 x = rb_rational_canonicalize(x);
918 y = rb_rational_canonicalize(y);
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
948rb_complex_div(VALUE self, VALUE other)
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
970f_reciprocal(VALUE x)
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
985rb_complex_pow(VALUE self, VALUE other)
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_BIGNUM_TYPE_P(other))
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 RBOOL(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 RBOOL(f_eqeq_p(dat->real, other) && f_zero_p(dat->imag));
1095 }
1096 return RBOOL(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_real_p_m(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: */
1322st_index_t
1323rb_complex_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 v;
1335}
1336
1337static VALUE
1338nucomp_hash(VALUE self)
1339{
1340 return ST2FIX(rb_complex_hash(self));
1341}
1342
1343/* :nodoc: */
1344static VALUE
1345nucomp_eql_p(VALUE self, VALUE other)
1346{
1347 if (RB_TYPE_P(other, T_COMPLEX)) {
1348 get_dat2(self, other);
1349
1350 return RBOOL((CLASS_OF(adat->real) == CLASS_OF(bdat->real)) &&
1351 (CLASS_OF(adat->imag) == CLASS_OF(bdat->imag)) &&
1352 f_eqeq_p(self, other));
1353
1354 }
1355 return Qfalse;
1356}
1357
1358inline static int
1359f_signbit(VALUE x)
1360{
1361 if (RB_FLOAT_TYPE_P(x)) {
1362 double f = RFLOAT_VALUE(x);
1363 return !isnan(f) && signbit(f);
1364 }
1365 return f_negative_p(x);
1366}
1367
1368inline static int
1369f_tpositive_p(VALUE x)
1370{
1371 return !f_signbit(x);
1372}
1373
1374static VALUE
1375f_format(VALUE self, VALUE (*func)(VALUE))
1376{
1377 VALUE s;
1378 int impos;
1379
1380 get_dat1(self);
1381
1382 impos = f_tpositive_p(dat->imag);
1383
1384 s = (*func)(dat->real);
1385 rb_str_cat2(s, !impos ? "-" : "+");
1386
1387 rb_str_concat(s, (*func)(f_abs(dat->imag)));
1388 if (!rb_isdigit(RSTRING_PTR(s)[RSTRING_LEN(s) - 1]))
1389 rb_str_cat2(s, "*");
1390 rb_str_cat2(s, "i");
1391
1392 return s;
1393}
1394
1395/*
1396 * call-seq:
1397 * cmp.to_s -> string
1398 *
1399 * Returns the value as a string.
1400 *
1401 * Complex(2).to_s #=> "2+0i"
1402 * Complex('-8/6').to_s #=> "-4/3+0i"
1403 * Complex('1/2i').to_s #=> "0+1/2i"
1404 * Complex(0, Float::INFINITY).to_s #=> "0+Infinity*i"
1405 * Complex(Float::NAN, Float::NAN).to_s #=> "NaN+NaN*i"
1406 */
1407static VALUE
1408nucomp_to_s(VALUE self)
1409{
1410 return f_format(self, rb_String);
1411}
1412
1413/*
1414 * call-seq:
1415 * cmp.inspect -> string
1416 *
1417 * Returns the value as a string for inspection.
1418 *
1419 * Complex(2).inspect #=> "(2+0i)"
1420 * Complex('-8/6').inspect #=> "((-4/3)+0i)"
1421 * Complex('1/2i').inspect #=> "(0+(1/2)*i)"
1422 * Complex(0, Float::INFINITY).inspect #=> "(0+Infinity*i)"
1423 * Complex(Float::NAN, Float::NAN).inspect #=> "(NaN+NaN*i)"
1424 */
1425static VALUE
1426nucomp_inspect(VALUE self)
1427{
1428 VALUE s;
1429
1430 s = rb_usascii_str_new2("(");
1431 rb_str_concat(s, f_format(self, rb_inspect));
1432 rb_str_cat2(s, ")");
1433
1434 return s;
1435}
1436
1437#define FINITE_TYPE_P(v) (RB_INTEGER_TYPE_P(v) || RB_TYPE_P(v, T_RATIONAL))
1438
1439/*
1440 * call-seq:
1441 * cmp.finite? -> true or false
1442 *
1443 * Returns +true+ if +cmp+'s real and imaginary parts are both finite numbers,
1444 * otherwise returns +false+.
1445 */
1446static VALUE
1447rb_complex_finite_p(VALUE self)
1448{
1449 get_dat1(self);
1450
1451 return RBOOL(f_finite_p(dat->real) && f_finite_p(dat->imag));
1452}
1453
1454/*
1455 * call-seq:
1456 * cmp.infinite? -> nil or 1
1457 *
1458 * Returns +1+ if +cmp+'s real or imaginary part is an infinite number,
1459 * otherwise returns +nil+.
1460 *
1461 * For example:
1462 *
1463 * (1+1i).infinite? #=> nil
1464 * (Float::INFINITY + 1i).infinite? #=> 1
1465 */
1466static VALUE
1467rb_complex_infinite_p(VALUE self)
1468{
1469 get_dat1(self);
1470
1471 if (!f_infinite_p(dat->real) && !f_infinite_p(dat->imag)) {
1472 return Qnil;
1473 }
1474 return ONE;
1475}
1476
1477/* :nodoc: */
1478static VALUE
1479nucomp_dumper(VALUE self)
1480{
1481 return self;
1482}
1483
1484/* :nodoc: */
1485static VALUE
1486nucomp_loader(VALUE self, VALUE a)
1487{
1488 get_dat1(self);
1489
1490 RCOMPLEX_SET_REAL(dat, rb_ivar_get(a, id_i_real));
1491 RCOMPLEX_SET_IMAG(dat, rb_ivar_get(a, id_i_imag));
1492 OBJ_FREEZE_RAW(self);
1493
1494 return self;
1495}
1496
1497/* :nodoc: */
1498static VALUE
1499nucomp_marshal_dump(VALUE self)
1500{
1501 VALUE a;
1502 get_dat1(self);
1503
1504 a = rb_assoc_new(dat->real, dat->imag);
1505 rb_copy_generic_ivar(a, self);
1506 return a;
1507}
1508
1509/* :nodoc: */
1510static VALUE
1511nucomp_marshal_load(VALUE self, VALUE a)
1512{
1513 Check_Type(a, T_ARRAY);
1514 if (RARRAY_LEN(a) != 2)
1515 rb_raise(rb_eArgError, "marshaled complex must have an array whose length is 2 but %ld", RARRAY_LEN(a));
1516 rb_ivar_set(self, id_i_real, RARRAY_AREF(a, 0));
1517 rb_ivar_set(self, id_i_imag, RARRAY_AREF(a, 1));
1518 return self;
1519}
1520
1521VALUE
1522rb_complex_raw(VALUE x, VALUE y)
1523{
1524 return nucomp_s_new_internal(rb_cComplex, x, y);
1525}
1526
1527VALUE
1528rb_complex_new(VALUE x, VALUE y)
1529{
1530 return nucomp_s_canonicalize_internal(rb_cComplex, x, y);
1531}
1532
1533VALUE
1534rb_complex_new_polar(VALUE x, VALUE y)
1535{
1536 return f_complex_polar(rb_cComplex, x, y);
1537}
1538
1539VALUE
1540rb_complex_polar(VALUE x, VALUE y)
1541{
1542 return rb_complex_new_polar(x, y);
1543}
1544
1545VALUE
1546rb_Complex(VALUE x, VALUE y)
1547{
1548 VALUE a[2];
1549 a[0] = x;
1550 a[1] = y;
1551 return nucomp_s_convert(2, a, rb_cComplex);
1552}
1553
1554VALUE
1555rb_dbl_complex_new(double real, double imag)
1556{
1557 return rb_complex_raw(DBL2NUM(real), DBL2NUM(imag));
1558}
1559
1560/*
1561 * call-seq:
1562 * cmp.to_i -> integer
1563 *
1564 * Returns the value as an integer if possible (the imaginary part
1565 * should be exactly zero).
1566 *
1567 * Complex(1, 0).to_i #=> 1
1568 * Complex(1, 0.0).to_i # RangeError
1569 * Complex(1, 2).to_i # RangeError
1570 */
1571static VALUE
1572nucomp_to_i(VALUE self)
1573{
1574 get_dat1(self);
1575
1576 if (!k_exact_zero_p(dat->imag)) {
1577 rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Integer",
1578 self);
1579 }
1580 return f_to_i(dat->real);
1581}
1582
1583/*
1584 * call-seq:
1585 * cmp.to_f -> float
1586 *
1587 * Returns the value as a float if possible (the imaginary part should
1588 * be exactly zero).
1589 *
1590 * Complex(1, 0).to_f #=> 1.0
1591 * Complex(1, 0.0).to_f # RangeError
1592 * Complex(1, 2).to_f # RangeError
1593 */
1594static VALUE
1595nucomp_to_f(VALUE self)
1596{
1597 get_dat1(self);
1598
1599 if (!k_exact_zero_p(dat->imag)) {
1600 rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Float",
1601 self);
1602 }
1603 return f_to_f(dat->real);
1604}
1605
1606/*
1607 * call-seq:
1608 * cmp.to_r -> rational
1609 *
1610 * Returns the value as a rational if possible (the imaginary part
1611 * should be exactly zero).
1612 *
1613 * Complex(1, 0).to_r #=> (1/1)
1614 * Complex(1, 0.0).to_r # RangeError
1615 * Complex(1, 2).to_r # RangeError
1616 *
1617 * See rationalize.
1618 */
1619static VALUE
1620nucomp_to_r(VALUE self)
1621{
1622 get_dat1(self);
1623
1624 if (!k_exact_zero_p(dat->imag)) {
1625 rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Rational",
1626 self);
1627 }
1628 return f_to_r(dat->real);
1629}
1630
1631/*
1632 * call-seq:
1633 * cmp.rationalize([eps]) -> rational
1634 *
1635 * Returns the value as a rational if possible (the imaginary part
1636 * should be exactly zero).
1637 *
1638 * Complex(1.0/3, 0).rationalize #=> (1/3)
1639 * Complex(1, 0.0).rationalize # RangeError
1640 * Complex(1, 2).rationalize # RangeError
1641 *
1642 * See to_r.
1643 */
1644static VALUE
1645nucomp_rationalize(int argc, VALUE *argv, VALUE self)
1646{
1647 get_dat1(self);
1648
1649 rb_check_arity(argc, 0, 1);
1650
1651 if (!k_exact_zero_p(dat->imag)) {
1652 rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Rational",
1653 self);
1654 }
1655 return rb_funcallv(dat->real, id_rationalize, argc, argv);
1656}
1657
1658/*
1659 * call-seq:
1660 * complex.to_c -> self
1661 *
1662 * Returns self.
1663 *
1664 * Complex(2).to_c #=> (2+0i)
1665 * Complex(-8, 6).to_c #=> (-8+6i)
1666 */
1667static VALUE
1668nucomp_to_c(VALUE self)
1669{
1670 return self;
1671}
1672
1673/*
1674 * call-seq:
1675 * nil.to_c -> (0+0i)
1676 *
1677 * Returns zero as a complex.
1678 */
1679static VALUE
1680nilclass_to_c(VALUE self)
1681{
1682 return rb_complex_new1(INT2FIX(0));
1683}
1684
1685/*
1686 * call-seq:
1687 * num.to_c -> complex
1688 *
1689 * Returns the value as a complex.
1690 */
1691static VALUE
1692numeric_to_c(VALUE self)
1693{
1694 return rb_complex_new1(self);
1695}
1696
1697inline static int
1698issign(int c)
1699{
1700 return (c == '-' || c == '+');
1701}
1702
1703static int
1704read_sign(const char **s,
1705 char **b)
1706{
1707 int sign = '?';
1708
1709 if (issign(**s)) {
1710 sign = **b = **s;
1711 (*s)++;
1712 (*b)++;
1713 }
1714 return sign;
1715}
1716
1717inline static int
1718isdecimal(int c)
1719{
1720 return isdigit((unsigned char)c);
1721}
1722
1723static int
1724read_digits(const char **s, int strict,
1725 char **b)
1726{
1727 int us = 1;
1728
1729 if (!isdecimal(**s))
1730 return 0;
1731
1732 while (isdecimal(**s) || **s == '_') {
1733 if (**s == '_') {
1734 if (strict) {
1735 if (us)
1736 return 0;
1737 }
1738 us = 1;
1739 }
1740 else {
1741 **b = **s;
1742 (*b)++;
1743 us = 0;
1744 }
1745 (*s)++;
1746 }
1747 if (us)
1748 do {
1749 (*s)--;
1750 } while (**s == '_');
1751 return 1;
1752}
1753
1754inline static int
1755islettere(int c)
1756{
1757 return (c == 'e' || c == 'E');
1758}
1759
1760static int
1761read_num(const char **s, int strict,
1762 char **b)
1763{
1764 if (**s != '.') {
1765 if (!read_digits(s, strict, b))
1766 return 0;
1767 }
1768
1769 if (**s == '.') {
1770 **b = **s;
1771 (*s)++;
1772 (*b)++;
1773 if (!read_digits(s, strict, b)) {
1774 (*b)--;
1775 return 0;
1776 }
1777 }
1778
1779 if (islettere(**s)) {
1780 **b = **s;
1781 (*s)++;
1782 (*b)++;
1783 read_sign(s, b);
1784 if (!read_digits(s, strict, b)) {
1785 (*b)--;
1786 return 0;
1787 }
1788 }
1789 return 1;
1790}
1791
1792inline static int
1793read_den(const char **s, int strict,
1794 char **b)
1795{
1796 if (!read_digits(s, strict, b))
1797 return 0;
1798 return 1;
1799}
1800
1801static int
1802read_rat_nos(const char **s, int strict,
1803 char **b)
1804{
1805 if (!read_num(s, strict, b))
1806 return 0;
1807 if (**s == '/') {
1808 **b = **s;
1809 (*s)++;
1810 (*b)++;
1811 if (!read_den(s, strict, b)) {
1812 (*b)--;
1813 return 0;
1814 }
1815 }
1816 return 1;
1817}
1818
1819static int
1820read_rat(const char **s, int strict,
1821 char **b)
1822{
1823 read_sign(s, b);
1824 if (!read_rat_nos(s, strict, b))
1825 return 0;
1826 return 1;
1827}
1828
1829inline static int
1830isimagunit(int c)
1831{
1832 return (c == 'i' || c == 'I' ||
1833 c == 'j' || c == 'J');
1834}
1835
1836static VALUE
1837str2num(char *s)
1838{
1839 if (strchr(s, '/'))
1840 return rb_cstr_to_rat(s, 0);
1841 if (strpbrk(s, ".eE"))
1842 return DBL2NUM(rb_cstr_to_dbl(s, 0));
1843 return rb_cstr_to_inum(s, 10, 0);
1844}
1845
1846static int
1847read_comp(const char **s, int strict,
1848 VALUE *ret, char **b)
1849{
1850 char *bb;
1851 int sign;
1852 VALUE num, num2;
1853
1854 bb = *b;
1855
1856 sign = read_sign(s, b);
1857
1858 if (isimagunit(**s)) {
1859 (*s)++;
1860 num = INT2FIX((sign == '-') ? -1 : + 1);
1861 *ret = rb_complex_new2(ZERO, num);
1862 return 1; /* e.g. "i" */
1863 }
1864
1865 if (!read_rat_nos(s, strict, b)) {
1866 **b = '\0';
1867 num = str2num(bb);
1868 *ret = rb_complex_new2(num, ZERO);
1869 return 0; /* e.g. "-" */
1870 }
1871 **b = '\0';
1872 num = str2num(bb);
1873
1874 if (isimagunit(**s)) {
1875 (*s)++;
1876 *ret = rb_complex_new2(ZERO, num);
1877 return 1; /* e.g. "3i" */
1878 }
1879
1880 if (**s == '@') {
1881 int st;
1882
1883 (*s)++;
1884 bb = *b;
1885 st = read_rat(s, strict, b);
1886 **b = '\0';
1887 if (strlen(bb) < 1 ||
1888 !isdecimal(*(bb + strlen(bb) - 1))) {
1889 *ret = rb_complex_new2(num, ZERO);
1890 return 0; /* e.g. "1@-" */
1891 }
1892 num2 = str2num(bb);
1893 *ret = rb_complex_new_polar(num, num2);
1894 if (!st)
1895 return 0; /* e.g. "1@2." */
1896 else
1897 return 1; /* e.g. "1@2" */
1898 }
1899
1900 if (issign(**s)) {
1901 bb = *b;
1902 sign = read_sign(s, b);
1903 if (isimagunit(**s))
1904 num2 = INT2FIX((sign == '-') ? -1 : + 1);
1905 else {
1906 if (!read_rat_nos(s, strict, b)) {
1907 *ret = rb_complex_new2(num, ZERO);
1908 return 0; /* e.g. "1+xi" */
1909 }
1910 **b = '\0';
1911 num2 = str2num(bb);
1912 }
1913 if (!isimagunit(**s)) {
1914 *ret = rb_complex_new2(num, ZERO);
1915 return 0; /* e.g. "1+3x" */
1916 }
1917 (*s)++;
1918 *ret = rb_complex_new2(num, num2);
1919 return 1; /* e.g. "1+2i" */
1920 }
1921 /* !(@, - or +) */
1922 {
1923 *ret = rb_complex_new2(num, ZERO);
1924 return 1; /* e.g. "3" */
1925 }
1926}
1927
1928inline static void
1929skip_ws(const char **s)
1930{
1931 while (isspace((unsigned char)**s))
1932 (*s)++;
1933}
1934
1935static int
1936parse_comp(const char *s, int strict, VALUE *num)
1937{
1938 char *buf, *b;
1939 VALUE tmp;
1940 int ret = 1;
1941
1942 buf = ALLOCV_N(char, tmp, strlen(s) + 1);
1943 b = buf;
1944
1945 skip_ws(&s);
1946 if (!read_comp(&s, strict, num, &b)) {
1947 ret = 0;
1948 }
1949 else {
1950 skip_ws(&s);
1951
1952 if (strict)
1953 if (*s != '\0')
1954 ret = 0;
1955 }
1956 ALLOCV_END(tmp);
1957
1958 return ret;
1959}
1960
1961static VALUE
1962string_to_c_strict(VALUE self, int raise)
1963{
1964 char *s;
1965 VALUE num;
1966
1967 rb_must_asciicompat(self);
1968
1969 s = RSTRING_PTR(self);
1970
1971 if (!s || memchr(s, '\0', RSTRING_LEN(self))) {
1972 if (!raise) return Qnil;
1973 rb_raise(rb_eArgError, "string contains null byte");
1974 }
1975
1976 if (s && s[RSTRING_LEN(self)]) {
1977 rb_str_modify(self);
1978 s = RSTRING_PTR(self);
1979 s[RSTRING_LEN(self)] = '\0';
1980 }
1981
1982 if (!s)
1983 s = (char *)"";
1984
1985 if (!parse_comp(s, 1, &num)) {
1986 if (!raise) return Qnil;
1987 rb_raise(rb_eArgError, "invalid value for convert(): %+"PRIsVALUE,
1988 self);
1989 }
1990
1991 return num;
1992}
1993
1994/*
1995 * call-seq:
1996 * str.to_c -> complex
1997 *
1998 * Returns a complex which denotes the string form. The parser
1999 * ignores leading whitespaces and trailing garbage. Any digit
2000 * sequences can be separated by an underscore. Returns zero for null
2001 * or garbage string.
2002 *
2003 * '9'.to_c #=> (9+0i)
2004 * '2.5'.to_c #=> (2.5+0i)
2005 * '2.5/1'.to_c #=> ((5/2)+0i)
2006 * '-3/2'.to_c #=> ((-3/2)+0i)
2007 * '-i'.to_c #=> (0-1i)
2008 * '45i'.to_c #=> (0+45i)
2009 * '3-4i'.to_c #=> (3-4i)
2010 * '-4e2-4e-2i'.to_c #=> (-400.0-0.04i)
2011 * '-0.0-0.0i'.to_c #=> (-0.0-0.0i)
2012 * '1/2+3/4i'.to_c #=> ((1/2)+(3/4)*i)
2013 * 'ruby'.to_c #=> (0+0i)
2014 *
2015 * See Kernel.Complex.
2016 */
2017static VALUE
2018string_to_c(VALUE self)
2019{
2020 char *s;
2021 VALUE num;
2022
2023 rb_must_asciicompat(self);
2024
2025 s = RSTRING_PTR(self);
2026
2027 if (s && s[RSTRING_LEN(self)]) {
2028 rb_str_modify(self);
2029 s = RSTRING_PTR(self);
2030 s[RSTRING_LEN(self)] = '\0';
2031 }
2032
2033 if (!s)
2034 s = (char *)"";
2035
2036 (void)parse_comp(s, 0, &num);
2037
2038 return num;
2039}
2040
2041static VALUE
2042to_complex(VALUE val)
2043{
2044 return rb_convert_type(val, T_COMPLEX, "Complex", "to_c");
2045}
2046
2047static VALUE
2048nucomp_convert(VALUE klass, VALUE a1, VALUE a2, int raise)
2049{
2050 if (NIL_P(a1) || NIL_P(a2)) {
2051 if (!raise) return Qnil;
2052 rb_raise(rb_eTypeError, "can't convert nil into Complex");
2053 }
2054
2055 if (RB_TYPE_P(a1, T_STRING)) {
2056 a1 = string_to_c_strict(a1, raise);
2057 if (NIL_P(a1)) return Qnil;
2058 }
2059
2060 if (RB_TYPE_P(a2, T_STRING)) {
2061 a2 = string_to_c_strict(a2, raise);
2062 if (NIL_P(a2)) return Qnil;
2063 }
2064
2065 if (RB_TYPE_P(a1, T_COMPLEX)) {
2066 {
2067 get_dat1(a1);
2068
2069 if (k_exact_zero_p(dat->imag))
2070 a1 = dat->real;
2071 }
2072 }
2073
2074 if (RB_TYPE_P(a2, T_COMPLEX)) {
2075 {
2076 get_dat1(a2);
2077
2078 if (k_exact_zero_p(dat->imag))
2079 a2 = dat->real;
2080 }
2081 }
2082
2083 if (RB_TYPE_P(a1, T_COMPLEX)) {
2084 if (a2 == Qundef || (k_exact_zero_p(a2)))
2085 return a1;
2086 }
2087
2088 if (a2 == Qundef) {
2089 if (k_numeric_p(a1) && !f_real_p(a1))
2090 return a1;
2091 /* should raise exception for consistency */
2092 if (!k_numeric_p(a1)) {
2093 if (!raise)
2094 return rb_protect(to_complex, a1, NULL);
2095 return to_complex(a1);
2096 }
2097 }
2098 else {
2099 if ((k_numeric_p(a1) && k_numeric_p(a2)) &&
2100 (!f_real_p(a1) || !f_real_p(a2)))
2101 return f_add(a1,
2102 f_mul(a2,
2103 f_complex_new_bang2(rb_cComplex, ZERO, ONE)));
2104 }
2105
2106 {
2107 int argc;
2108 VALUE argv2[2];
2109 argv2[0] = a1;
2110 if (a2 == Qundef) {
2111 argv2[1] = Qnil;
2112 argc = 1;
2113 }
2114 else {
2115 if (!raise && !RB_INTEGER_TYPE_P(a2) && !RB_FLOAT_TYPE_P(a2) && !RB_TYPE_P(a2, T_RATIONAL))
2116 return Qnil;
2117 argv2[1] = a2;
2118 argc = 2;
2119 }
2120 return nucomp_s_new(argc, argv2, klass);
2121 }
2122}
2123
2124static VALUE
2125nucomp_s_convert(int argc, VALUE *argv, VALUE klass)
2126{
2127 VALUE a1, a2;
2128
2129 if (rb_scan_args(argc, argv, "11", &a1, &a2) == 1) {
2130 a2 = Qundef;
2131 }
2132
2133 return nucomp_convert(klass, a1, a2, TRUE);
2134}
2135
2136/*
2137 * call-seq:
2138 * num.real -> self
2139 *
2140 * Returns self.
2141 */
2142static VALUE
2143numeric_real(VALUE self)
2144{
2145 return self;
2146}
2147
2148/*
2149 * call-seq:
2150 * num.imag -> 0
2151 * num.imaginary -> 0
2152 *
2153 * Returns zero.
2154 */
2155static VALUE
2156numeric_imag(VALUE self)
2157{
2158 return INT2FIX(0);
2159}
2160
2161/*
2162 * call-seq:
2163 * num.abs2 -> real
2164 *
2165 * Returns square of self.
2166 */
2167static VALUE
2168numeric_abs2(VALUE self)
2169{
2170 return f_mul(self, self);
2171}
2172
2173/*
2174 * call-seq:
2175 * num.arg -> 0 or float
2176 * num.angle -> 0 or float
2177 * num.phase -> 0 or float
2178 *
2179 * Returns 0 if the value is positive, pi otherwise.
2180 */
2181static VALUE
2182numeric_arg(VALUE self)
2183{
2184 if (f_positive_p(self))
2185 return INT2FIX(0);
2186 return DBL2NUM(M_PI);
2187}
2188
2189/*
2190 * call-seq:
2191 * num.rect -> array
2192 * num.rectangular -> array
2193 *
2194 * Returns an array; [num, 0].
2195 */
2196static VALUE
2197numeric_rect(VALUE self)
2198{
2199 return rb_assoc_new(self, INT2FIX(0));
2200}
2201
2202/*
2203 * call-seq:
2204 * num.polar -> array
2205 *
2206 * Returns an array; [num.abs, num.arg].
2207 */
2208static VALUE
2209numeric_polar(VALUE self)
2210{
2211 VALUE abs, arg;
2212
2213 if (RB_INTEGER_TYPE_P(self)) {
2214 abs = rb_int_abs(self);
2215 arg = numeric_arg(self);
2216 }
2217 else if (RB_FLOAT_TYPE_P(self)) {
2218 abs = rb_float_abs(self);
2219 arg = float_arg(self);
2220 }
2221 else if (RB_TYPE_P(self, T_RATIONAL)) {
2222 abs = rb_rational_abs(self);
2223 arg = numeric_arg(self);
2224 }
2225 else {
2226 abs = f_abs(self);
2227 arg = f_arg(self);
2228 }
2229 return rb_assoc_new(abs, arg);
2230}
2231
2232/*
2233 * call-seq:
2234 * num.conj -> self
2235 * num.conjugate -> self
2236 *
2237 * Returns self.
2238 */
2239static VALUE
2240numeric_conj(VALUE self)
2241{
2242 return self;
2243}
2244
2245/*
2246 * call-seq:
2247 * flo.arg -> 0 or float
2248 * flo.angle -> 0 or float
2249 * flo.phase -> 0 or float
2250 *
2251 * Returns 0 if the value is positive, pi otherwise.
2252 */
2253static VALUE
2254float_arg(VALUE self)
2255{
2256 if (isnan(RFLOAT_VALUE(self)))
2257 return self;
2258 if (f_tpositive_p(self))
2259 return INT2FIX(0);
2260 return rb_const_get(rb_mMath, id_PI);
2261}
2262
2263/*
2264 * A complex number can be represented as a paired real number with
2265 * imaginary unit; a+bi. Where a is real part, b is imaginary part
2266 * and i is imaginary unit. Real a equals complex a+0i
2267 * mathematically.
2268 *
2269 * You can create a \Complex object explicitly with:
2270 *
2271 * - A {complex literal}[doc/syntax/literals_rdoc.html#label-Complex+Literals].
2272 *
2273 * You can convert certain objects to \Complex objects with:
2274 *
2275 * - \Method {Complex}[Kernel.html#method-i-Complex].
2276 *
2277 * Complex object can be created as literal, and also by using
2278 * Kernel#Complex, Complex::rect, Complex::polar or to_c method.
2279 *
2280 * 2+1i #=> (2+1i)
2281 * Complex(1) #=> (1+0i)
2282 * Complex(2, 3) #=> (2+3i)
2283 * Complex.polar(2, 3) #=> (-1.9799849932008908+0.2822400161197344i)
2284 * 3.to_c #=> (3+0i)
2285 *
2286 * You can also create complex object from floating-point numbers or
2287 * strings.
2288 *
2289 * Complex(0.3) #=> (0.3+0i)
2290 * Complex('0.3-0.5i') #=> (0.3-0.5i)
2291 * Complex('2/3+3/4i') #=> ((2/3)+(3/4)*i)
2292 * Complex('1@2') #=> (-0.4161468365471424+0.9092974268256817i)
2293 *
2294 * 0.3.to_c #=> (0.3+0i)
2295 * '0.3-0.5i'.to_c #=> (0.3-0.5i)
2296 * '2/3+3/4i'.to_c #=> ((2/3)+(3/4)*i)
2297 * '1@2'.to_c #=> (-0.4161468365471424+0.9092974268256817i)
2298 *
2299 * A complex object is either an exact or an inexact number.
2300 *
2301 * Complex(1, 1) / 2 #=> ((1/2)+(1/2)*i)
2302 * Complex(1, 1) / 2.0 #=> (0.5+0.5i)
2303 */
2304void
2305Init_Complex(void)
2306{
2307 VALUE compat;
2308 id_abs = rb_intern_const("abs");
2309 id_arg = rb_intern_const("arg");
2310 id_denominator = rb_intern_const("denominator");
2311 id_numerator = rb_intern_const("numerator");
2312 id_real_p = rb_intern_const("real?");
2313 id_i_real = rb_intern_const("@real");
2314 id_i_imag = rb_intern_const("@image"); /* @image, not @imag */
2315 id_finite_p = rb_intern_const("finite?");
2316 id_infinite_p = rb_intern_const("infinite?");
2317 id_rationalize = rb_intern_const("rationalize");
2318 id_PI = rb_intern_const("PI");
2319
2321
2322 rb_define_alloc_func(rb_cComplex, nucomp_s_alloc);
2323 rb_undef_method(CLASS_OF(rb_cComplex), "allocate");
2324
2326
2327 rb_define_singleton_method(rb_cComplex, "rectangular", nucomp_s_new, -1);
2328 rb_define_singleton_method(rb_cComplex, "rect", nucomp_s_new, -1);
2329 rb_define_singleton_method(rb_cComplex, "polar", nucomp_s_polar, -1);
2330
2331 rb_define_global_function("Complex", nucomp_f_complex, -1);
2332
2333 rb_undef_methods_from(rb_cComplex, RCLASS_ORIGIN(rb_mComparable));
2336 rb_undef_method(rb_cComplex, "divmod");
2337 rb_undef_method(rb_cComplex, "floor");
2339 rb_undef_method(rb_cComplex, "modulo");
2340 rb_undef_method(rb_cComplex, "remainder");
2341 rb_undef_method(rb_cComplex, "round");
2343 rb_undef_method(rb_cComplex, "truncate");
2345
2349
2355 rb_define_method(rb_cComplex, "quo", nucomp_quo, 1);
2356 rb_define_method(rb_cComplex, "fdiv", nucomp_fdiv, 1);
2358
2359 rb_define_method(rb_cComplex, "==", nucomp_eqeq_p, 1);
2360 rb_define_method(rb_cComplex, "<=>", nucomp_cmp, 1);
2361 rb_define_method(rb_cComplex, "coerce", nucomp_coerce, 1);
2362
2365 rb_define_method(rb_cComplex, "abs2", nucomp_abs2, 0);
2369 rb_define_method(rb_cComplex, "rectangular", nucomp_rect, 0);
2370 rb_define_method(rb_cComplex, "rect", nucomp_rect, 0);
2371 rb_define_method(rb_cComplex, "polar", nucomp_polar, 0);
2374
2375 rb_define_method(rb_cComplex, "real?", nucomp_real_p_m, 0);
2376
2377 rb_define_method(rb_cComplex, "numerator", nucomp_numerator, 0);
2378 rb_define_method(rb_cComplex, "denominator", nucomp_denominator, 0);
2379
2380 rb_define_method(rb_cComplex, "hash", nucomp_hash, 0);
2381 rb_define_method(rb_cComplex, "eql?", nucomp_eql_p, 1);
2382
2383 rb_define_method(rb_cComplex, "to_s", nucomp_to_s, 0);
2384 rb_define_method(rb_cComplex, "inspect", nucomp_inspect, 0);
2385
2386 rb_undef_method(rb_cComplex, "positive?");
2387 rb_undef_method(rb_cComplex, "negative?");
2388
2389 rb_define_method(rb_cComplex, "finite?", rb_complex_finite_p, 0);
2390 rb_define_method(rb_cComplex, "infinite?", rb_complex_infinite_p, 0);
2391
2392 rb_define_private_method(rb_cComplex, "marshal_dump", nucomp_marshal_dump, 0);
2393 /* :nodoc: */
2394 compat = rb_define_class_under(rb_cComplex, "compatible", rb_cObject);
2395 rb_define_private_method(compat, "marshal_load", nucomp_marshal_load, 1);
2396 rb_marshal_define_compat(rb_cComplex, compat, nucomp_dumper, nucomp_loader);
2397
2398 rb_define_method(rb_cComplex, "to_i", nucomp_to_i, 0);
2399 rb_define_method(rb_cComplex, "to_f", nucomp_to_f, 0);
2400 rb_define_method(rb_cComplex, "to_r", nucomp_to_r, 0);
2401 rb_define_method(rb_cComplex, "rationalize", nucomp_rationalize, -1);
2402 rb_define_method(rb_cComplex, "to_c", nucomp_to_c, 0);
2403 rb_define_method(rb_cNilClass, "to_c", nilclass_to_c, 0);
2404 rb_define_method(rb_cNumeric, "to_c", numeric_to_c, 0);
2405
2406 rb_define_method(rb_cString, "to_c", string_to_c, 0);
2407
2408 rb_define_private_method(CLASS_OF(rb_cComplex), "convert", nucomp_s_convert, -1);
2409
2410 rb_define_method(rb_cNumeric, "real", numeric_real, 0);
2411 rb_define_method(rb_cNumeric, "imaginary", numeric_imag, 0);
2412 rb_define_method(rb_cNumeric, "imag", numeric_imag, 0);
2413 rb_define_method(rb_cNumeric, "abs2", numeric_abs2, 0);
2414 rb_define_method(rb_cNumeric, "arg", numeric_arg, 0);
2415 rb_define_method(rb_cNumeric, "angle", numeric_arg, 0);
2416 rb_define_method(rb_cNumeric, "phase", numeric_arg, 0);
2417 rb_define_method(rb_cNumeric, "rectangular", numeric_rect, 0);
2418 rb_define_method(rb_cNumeric, "rect", numeric_rect, 0);
2419 rb_define_method(rb_cNumeric, "polar", numeric_polar, 0);
2420 rb_define_method(rb_cNumeric, "conjugate", numeric_conj, 0);
2421 rb_define_method(rb_cNumeric, "conj", numeric_conj, 0);
2422
2423 rb_define_method(rb_cFloat, "arg", float_arg, 0);
2424 rb_define_method(rb_cFloat, "angle", float_arg, 0);
2425 rb_define_method(rb_cFloat, "phase", float_arg, 0);
2426
2427 /*
2428 * The imaginary unit.
2429 */
2431 f_complex_new_bang2(rb_cComplex, ZERO, ONE));
2432
2433#if !USE_FLONUM
2434 rb_gc_register_mark_object(RFLOAT_0 = DBL2NUM(0.0));
2435#endif
2436
2437 rb_provide("complex.so"); /* for backward compatibility */
2438}
static int rb_isdigit(int c)
Our own locale-insensitive version of isdigit(3).
Definition: ctype.h:302
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
Definition: cxxanyargs.hpp:685
#define rb_define_private_method(klass, mid, func, arity)
Defines klass#mid and makes it private.
Definition: cxxanyargs.hpp:677
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:837
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:869
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
Definition: class.c:1938
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
Definition: class.c:2406
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a method.
Definition: class.c:1914
void rb_define_global_function(const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a global function.
Definition: class.c:2110
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
Definition: value_type.h:59
#define NEWOBJ_OF
Old name of RB_NEWOBJ_OF.
Definition: newobj.h:61
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition: value_type.h:87
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition: double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition: value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition: long.h:48
#define OBJ_FREEZE_RAW
Old name of RB_OBJ_FREEZE_RAW.
Definition: fl_type.h:144
#define CLASS_OF
Old name of rb_class_of.
Definition: globals.h:203
#define LONG2FIX
Old name of RB_INT2FIX.
Definition: long.h:49
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition: value_type.h:76
#define NUM2DBL
Old name of rb_num2dbl.
Definition: double.h:27
VALUE rb_complex_polar(VALUE x, VALUE y)
Old name of rb_complex_new_polar.
Definition: complex.c:1540
#define rb_usascii_str_new2
Old name of rb_usascii_str_new_cstr.
Definition: string.h:1744
#define FLONUM_P
Old name of RB_FLONUM_P.
#define ST2FIX
Old name of RB_ST2FIX.
Definition: st_data_t.h:33
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition: long.h:46
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition: value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition: memory.h:399
#define FL_WB_PROTECTED
Old name of RUBY_FL_WB_PROTECTED.
Definition: fl_type.h:59
#define DBL2NUM
Old name of rb_float_new.
Definition: double.h:29
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition: long.h:51
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition: memory.h:400
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
Definition: error.c:3021
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports always regardless of runtime -W flag.
Definition: error.c:418
VALUE rb_cRational
Rational class.
Definition: rational.c:41
VALUE rb_convert_type(VALUE val, int type, const char *name, const char *mid)
Converts an object into another type.
Definition: object.c:2906
VALUE rb_cComplex
Complex class.
Definition: complex.c:38
VALUE rb_mMath
Math module.
Definition: math.c:29
VALUE rb_cInteger
Module class.
Definition: numeric.c:192
VALUE rb_cNumeric
Numeric class.
Definition: numeric.c:190
double rb_cstr_to_dbl(const char *str, int mode)
Converts a textual representation of a real number into a numeric, which is the nearest value that th...
Definition: object.c:3284
VALUE rb_mComparable
Comparable module.
Definition: compar.c:19
VALUE rb_cFloat
Float class.
Definition: numeric.c:191
VALUE rb_cString
String class.
Definition: string.c:80
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition: vm_eval.c:1102
VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcall(), except it takes the method arguments as a C array.
Definition: vm_eval.c:1061
void rb_gc_register_mark_object(VALUE object)
Inform the garbage collector that object is a live Ruby object that should not be moved.
Definition: gc.c:8686
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
Definition: array.c:976
VALUE rb_str_to_inum(VALUE str, int base, int badcheck)
Identical to rb_cstr2inum(), except it takes Ruby's strings instead of C's.
Definition: bignum.c:4280
VALUE rb_cstr_to_inum(const char *str, int base, int badcheck)
Parses C's string to convert into a Ruby's integer.
Definition: bignum.c:4022
int rb_cmpint(VALUE val, VALUE a, VALUE b)
Canonicalises the passed val, which is the return value of a <=> b, into C's {-1, 0,...
Definition: bignum.c:2935
VALUE rb_complex_uminus(VALUE z)
Performs negation of the passed object.
Definition: complex.c:758
VALUE rb_complex_div(VALUE x, VALUE y)
Performs division of the passed two objects.
Definition: complex.c:948
VALUE rb_complex_new(VALUE real, VALUE imag)
Constructs a Complex, by first multiplying the imaginary part with 1i then adds it to the real part.
Definition: complex.c:1528
VALUE rb_complex_plus(VALUE x, VALUE y)
Performs addition of the passed two objects.
Definition: complex.c:778
VALUE rb_complex_new_polar(VALUE abs, VALUE arg)
Constructs a Complex using polar representations.
Definition: complex.c:1534
VALUE rb_complex_arg(VALUE z)
Queries the argument (or the angle) of the passed object.
Definition: complex.c:1208
#define rb_complex_new2(x, y)
Just another name of rb_complex_new.
Definition: complex.h:77
VALUE rb_complex_raw(VALUE real, VALUE imag)
Identical to rb_complex_new(), except it assumes both arguments are not instances of rb_cComplex.
Definition: complex.c:1522
VALUE rb_dbl_complex_new(double real, double imag)
Identical to rb_complex_new(), except it takes the arguments as C's double instead of Ruby's object.
Definition: complex.c:1555
VALUE rb_complex_abs(VALUE z)
Queries the absolute (or the magnitude) of the passed object.
Definition: complex.c:1161
VALUE rb_complex_real(VALUE z)
Queries the real part of the passed Complex.
Definition: complex.c:726
VALUE rb_complex_mul(VALUE x, VALUE y)
Performs multiplication of the passed two objects.
Definition: complex.c:872
VALUE rb_complex_conjugate(VALUE z)
Performs complex conjugation of the passed object.
Definition: complex.c:1254
VALUE rb_Complex(VALUE real, VALUE imag)
Converts various values into a Complex.
Definition: complex.c:1546
VALUE rb_complex_minus(VALUE x, VALUE y)
Performs subtraction of the passed two objects.
Definition: complex.c:812
#define rb_complex_new1(x)
Shorthand of x+0i.
Definition: complex.h:74
VALUE rb_complex_pow(VALUE base, VALUE exp)
Performs exponentiation of the passed two objects.
Definition: complex.c:985
VALUE rb_complex_imag(VALUE z)
Queries the imaginary part of the passed Complex.
Definition: complex.c:743
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition: error.h:294
VALUE rb_hash(VALUE obj)
Calculates a message authentication code of the passed object.
Definition: hash.c:227
void rb_provide(const char *feature)
Declares that the given feature is already provided by someone else.
Definition: load.c:638
VALUE rb_num_coerce_bin(VALUE lhs, VALUE rhs, ID op)
Coerced binary operation.
Definition: numeric.c:471
VALUE rb_protect(VALUE(*func)(VALUE args), VALUE args, int *state)
Protects a function call from potential global escapes from the function.
st_index_t rb_memhash(const void *ptr, long len)
This is a universal hash function.
Definition: random.c:1720
VALUE rb_str_cat2(VALUE, const char *)
Just another name of rb_str_cat_cstr.
void rb_str_modify(VALUE str)
Declares that the string is about to be modified.
Definition: string.c:2459
void rb_must_asciicompat(VALUE obj)
Asserts that the given string's encoding is (Ruby's definition of) ASCII compatible.
Definition: string.c:2511
VALUE rb_str_concat(VALUE dst, VALUE src)
Identical to rb_str_append(), except it also accepts an integer as a codepoint.
Definition: string.c:3418
VALUE rb_const_get(VALUE space, ID name)
Identical to rb_const_defined(), except it returns the actual defined value.
Definition: variable.c:2733
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition: variable.c:1575
VALUE rb_ivar_get(VALUE obj, ID name)
Identical to rb_iv_get(), except it accepts the name as an ID instead of a C string.
Definition: variable.c:1285
int rb_method_basic_definition_p(VALUE klass, ID mid)
Well... Let us hesitate from describing what a "basic definition" is.
Definition: vm_method.c:2643
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition: symbol.h:276
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
Definition: variable.c:3253
void rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE(*dumper)(VALUE), VALUE(*loader)(VALUE, VALUE))
Marshal format compatibility layer.
Definition: marshal.c:148
void rb_copy_generic_ivar(VALUE clone, VALUE obj)
Copies the list of instance variables.
Definition: variable.c:1719
#define RARRAY_LEN
Just another name of rb_array_len.
Definition: rarray.h:68
#define RARRAY_AREF(a, i)
Definition: rarray.h:588
#define RGENGC_WB_PROTECTED_COMPLEX
This is a compile-time flag to enable/disable write barrier for struct RComplex.
Definition: rgengc.h:162
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
Definition: rstring.h:483
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
Definition: rstring.h:497
#define RTEST
This is an old name of RB_TEST.
Internal header for Complex.
Definition: complex.h:13
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition: value.h:63
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition: value_type.h:263
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition: value_type.h:432
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition: value_type.h:375