Ruby: complex.c Source File

Ruby 3.2.5p208 (2024-07-26 revision 31d0f1a2e7dbfb60731d1f05b868e1d578cda493)

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
38 VALUE rb_cComplex;
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) &&
73 LIKELY(rb_method_basic_definition_p(rb_cInteger, idPLUS))) {
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) &&
87 LIKELY(rb_method_basic_definition_p(rb_cRational, idPLUS))) {
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) &&
140 LIKELY(rb_method_basic_definition_p(rb_cRational, idMULT))) {
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 bool
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 rb_equal(x, ZERO) != 0;
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{
394 NEWOBJ_OF(obj, struct RComplex, klass, T_COMPLEX | (RGENGC_WB_PROTECTED_COMPLEX ? FL_WB_PROTECTED : 0));
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
424WARN_UNUSED_RESULT(inline static VALUE nucomp_real_check(VALUE num));
425inline static VALUE
426nucomp_real_check(VALUE num)
427{
428 if (!RB_INTEGER_TYPE_P(num) &&
429 !RB_FLOAT_TYPE_P(num) &&
430 !RB_TYPE_P(num, T_RATIONAL)) {
431 if (RB_TYPE_P(num, T_COMPLEX) && nucomp_real_p(num)) {
432 VALUE real = RCOMPLEX(num)->real;
433 assert(!RB_TYPE_P(real, T_COMPLEX));
434 return real;
435 }
436 if (!k_numeric_p(num) || !f_real_p(num))
437 rb_raise(rb_eTypeError, "not a real");
438 }
439 return num;
440}
441
442inline static VALUE
443nucomp_s_canonicalize_internal(VALUE klass, VALUE real, VALUE imag)
444{
445 int complex_r, complex_i;
446 complex_r = RB_TYPE_P(real, T_COMPLEX);
447 complex_i = RB_TYPE_P(imag, T_COMPLEX);
448 if (!complex_r && !complex_i) {
449 return nucomp_s_new_internal(klass, real, imag);
450 }
451 else if (!complex_r) {
452 get_dat1(imag);
453
454 return nucomp_s_new_internal(klass,
455 f_sub(real, dat->imag),
456 f_add(ZERO, dat->real));
457 }
458 else if (!complex_i) {
459 get_dat1(real);
460
461 return nucomp_s_new_internal(klass,
462 dat->real,
463 f_add(dat->imag, imag));
464 }
465 else {
466 get_dat2(real, imag);
467
468 return nucomp_s_new_internal(klass,
469 f_sub(adat->real, bdat->imag),
470 f_add(adat->imag, bdat->real));
471 }
472}
473
474/*
475 * call-seq:
476 * Complex.rect(real[, imag]) -> complex
477 * Complex.rectangular(real[, imag]) -> complex
478 *
479 * Returns a complex object which denotes the given rectangular form.
480 *
481 * Complex.rectangular(1, 2) #=> (1+2i)
482 */
483static VALUE
484nucomp_s_new(int argc, VALUE *argv, VALUE klass)
485{
486 VALUE real, imag;
487
488 switch (rb_scan_args(argc, argv, "11", &real, &imag)) {
489 case 1:
490 real = nucomp_real_check(real);
491 imag = ZERO;
492 break;
493 default:
494 real = nucomp_real_check(real);
495 imag = nucomp_real_check(imag);
496 break;
497 }
498
499 return nucomp_s_new_internal(klass, real, imag);
500}
501
502inline static VALUE
503f_complex_new2(VALUE klass, VALUE x, VALUE y)
504{
505 if (RB_TYPE_P(x, T_COMPLEX)) {
506 get_dat1(x);
507 x = dat->real;
508 y = f_add(dat->imag, y);
509 }
510 return nucomp_s_canonicalize_internal(klass, x, y);
511}
512
513static VALUE nucomp_convert(VALUE klass, VALUE a1, VALUE a2, int raise);
514static VALUE nucomp_s_convert(int argc, VALUE *argv, VALUE klass);
515
516/*
517 * call-seq:
518 * Complex(x[, y], exception: true) -> numeric or nil
519 *
520 * Returns x+i*y;
521 *
522 * Complex(1, 2) #=> (1+2i)
523 * Complex('1+2i') #=> (1+2i)
524 * Complex(nil) #=> TypeError
525 * Complex(1, nil) #=> TypeError
526 *
527 * Complex(1, nil, exception: false) #=> nil
528 * Complex('1+2', exception: false) #=> nil
529 *
530 * Syntax of string form:
531 *
532 * string form = extra spaces , complex , extra spaces ;
533 * complex = real part | [ sign ] , imaginary part
534 * | real part , sign , imaginary part
535 * | rational , "@" , rational ;
536 * real part = rational ;
537 * imaginary part = imaginary unit | unsigned rational , imaginary unit ;
538 * rational = [ sign ] , unsigned rational ;
539 * unsigned rational = numerator | numerator , "/" , denominator ;
540 * numerator = integer part | fractional part | integer part , fractional part ;
541 * denominator = digits ;
542 * integer part = digits ;
543 * fractional part = "." , digits , [ ( "e" | "E" ) , [ sign ] , digits ] ;
544 * imaginary unit = "i" | "I" | "j" | "J" ;
545 * sign = "-" | "+" ;
546 * digits = digit , { digit | "_" , digit };
547 * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
548 * extra spaces = ? \s* ? ;
549 *
550 * See String#to_c.
551 */
552static VALUE
553nucomp_f_complex(int argc, VALUE *argv, VALUE klass)
554{
555 VALUE a1, a2, opts = Qnil;
556 int raise = TRUE;
557
558 if (rb_scan_args(argc, argv, "11:", &a1, &a2, &opts) == 1) {
559 a2 = Qundef;
560 }
561 if (!NIL_P(opts)) {
562 raise = rb_opts_exception_p(opts, raise);
563 }
564 if (argc > 0 && CLASS_OF(a1) == rb_cComplex && UNDEF_P(a2)) {
565 return a1;
566 }
567 return nucomp_convert(rb_cComplex, a1, a2, raise);
568}
569
570#define imp1(n) \
571inline static VALUE \
572m_##n##_bang(VALUE x)\
573{\
574 return rb_math_##n(x);\
575}
576
577imp1(cos)
578imp1(cosh)
579imp1(exp)
580
581static VALUE
582m_log_bang(VALUE x)
583{
584 return rb_math_log(1, &x);
585}
586
587imp1(sin)
588imp1(sinh)
589
590static VALUE
591m_cos(VALUE x)
592{
593 if (!RB_TYPE_P(x, T_COMPLEX))
594 return m_cos_bang(x);
595 {
596 get_dat1(x);
597 return f_complex_new2(rb_cComplex,
598 f_mul(m_cos_bang(dat->real),
599 m_cosh_bang(dat->imag)),
600 f_mul(f_negate(m_sin_bang(dat->real)),
601 m_sinh_bang(dat->imag)));
602 }
603}
604
605static VALUE
606m_sin(VALUE x)
607{
608 if (!RB_TYPE_P(x, T_COMPLEX))
609 return m_sin_bang(x);
610 {
611 get_dat1(x);
612 return f_complex_new2(rb_cComplex,
613 f_mul(m_sin_bang(dat->real),
614 m_cosh_bang(dat->imag)),
615 f_mul(m_cos_bang(dat->real),
616 m_sinh_bang(dat->imag)));
617 }
618}
619
620static VALUE
621f_complex_polar_real(VALUE klass, VALUE x, VALUE y)
622{
623 if (f_zero_p(x) || f_zero_p(y)) {
624 return nucomp_s_new_internal(klass, x, RFLOAT_0);
625 }
626 if (RB_FLOAT_TYPE_P(y)) {
627 const double arg = RFLOAT_VALUE(y);
628 if (arg == M_PI) {
629 x = f_negate(x);
630 y = RFLOAT_0;
631 }
632 else if (arg == M_PI_2) {
633 y = x;
634 x = RFLOAT_0;
635 }
636 else if (arg == M_PI_2+M_PI) {
637 y = f_negate(x);
638 x = RFLOAT_0;
639 }
640 else if (RB_FLOAT_TYPE_P(x)) {
641 const double abs = RFLOAT_VALUE(x);
642 const double real = abs * cos(arg), imag = abs * sin(arg);
643 x = DBL2NUM(real);
644 y = DBL2NUM(imag);
645 }
646 else {
647 const double ax = sin(arg), ay = cos(arg);
648 y = f_mul(x, DBL2NUM(ax));
649 x = f_mul(x, DBL2NUM(ay));
650 }
651 return nucomp_s_new_internal(klass, x, y);
652 }
653 return nucomp_s_canonicalize_internal(klass,
654 f_mul(x, m_cos(y)),
655 f_mul(x, m_sin(y)));
656}
657
658static VALUE
659f_complex_polar(VALUE klass, VALUE x, VALUE y)
660{
661 x = nucomp_real_check(x);
662 y = nucomp_real_check(y);
663 return f_complex_polar_real(klass, x, y);
664}
665
666#ifdef HAVE___COSPI
667# define cospi(x) __cospi(x)
668#else
669# define cospi(x) cos((x) * M_PI)
670#endif
671#ifdef HAVE___SINPI
672# define sinpi(x) __sinpi(x)
673#else
674# define sinpi(x) sin((x) * M_PI)
675#endif
676/* returns a Complex or Float of ang*PI-rotated abs */
677 VALUE
678rb_dbl_complex_new_polar_pi(double abs, double ang)
679{
680 double fi;
681 const double fr = modf(ang, &fi);
682 int pos = fr == +0.5;
683
684 if (pos || fr == -0.5) {
685 if ((modf(fi / 2.0, &fi) != fr) ^ pos) abs = -abs;
686 return rb_complex_new(RFLOAT_0, DBL2NUM(abs));
687 }
688 else if (fr == 0.0) {
689 if (modf(fi / 2.0, &fi) != 0.0) abs = -abs;
690 return DBL2NUM(abs);
691 }
692 else {
693 const double real = abs * cospi(ang), imag = abs * sinpi(ang);
694 return rb_complex_new(DBL2NUM(real), DBL2NUM(imag));
695 }
696}
697
698/*
699 * call-seq:
700 * Complex.polar(abs[, arg]) -> complex
701 *
702 * Returns a complex object which denotes the given polar form.
703 *
704 * Complex.polar(3, 0) #=> (3.0+0.0i)
705 * Complex.polar(3, Math::PI/2) #=> (1.836909530733566e-16+3.0i)
706 * Complex.polar(3, Math::PI) #=> (-3.0+3.673819061467132e-16i)
707 * Complex.polar(3, -Math::PI/2) #=> (1.836909530733566e-16-3.0i)
708 */
709static VALUE
710nucomp_s_polar(int argc, VALUE *argv, VALUE klass)
711{
712 VALUE abs, arg;
713
714 argc = rb_scan_args(argc, argv, "11", &abs, &arg);
715 abs = nucomp_real_check(abs);
716 if (argc == 2) {
717 arg = nucomp_real_check(arg);
718 }
719 else {
720 arg = ZERO;
721 }
722 return f_complex_polar_real(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 */
734 VALUE
735rb_complex_real(VALUE self)
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 */
751 VALUE
752rb_complex_imag(VALUE self)
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 */
766 VALUE
767rb_complex_uminus(VALUE self)
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 */
786 VALUE
787rb_complex_plus(VALUE self, VALUE other)
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 */
820 VALUE
821rb_complex_minus(VALUE self, VALUE other)
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, bool az, bool 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 bool arzero = f_zero_p(areal);
859 bool aizero = f_zero_p(aimag);
860 bool brzero = f_zero_p(breal);
861 bool 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 */
880 VALUE
881rb_complex_mul(VALUE self, VALUE other)
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) {
926 x = rb_rational_canonicalize(x);
927 y = rb_rational_canonicalize(y);
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 */
956 VALUE
957rb_complex_div(VALUE self, VALUE other)
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
979f_reciprocal(VALUE x)
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 */
993 VALUE
994rb_complex_pow(VALUE self, VALUE other)
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_BIGNUM_TYPE_P(other))
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 RBOOL(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 RBOOL(f_eqeq_p(dat->real, other) && f_zero_p(dat->imag));
1104 }
1105 return RBOOL(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);
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 (!k_numeric_p(other)) {
1133 return rb_num_coerce_cmp(self, other, idCmp);
1134 }
1135 if (!nucomp_real_p(self)) {
1136 return Qnil;
1137 }
1138 if (RB_TYPE_P(other, T_COMPLEX)) {
1139 if (nucomp_real_p(other)) {
1140 get_dat2(self, other);
1141 return rb_funcall(adat->real, idCmp, 1, bdat->real);
1142 }
1143 }
1144 else {
1145 get_dat1(self);
1146 if (f_real_p(other)) {
1147 return rb_funcall(dat->real, idCmp, 1, other);
1148 }
1149 else {
1150 return rb_num_coerce_cmp(dat->real, other, idCmp);
1151 }
1152 }
1153 return Qnil;
1154}
1155
1156/* :nodoc: */
1157static VALUE
1158nucomp_coerce(VALUE self, VALUE other)
1159{
1160 if (RB_TYPE_P(other, T_COMPLEX))
1161 return rb_assoc_new(other, self);
1162 if (k_numeric_p(other) && f_real_p(other))
1163 return rb_assoc_new(f_complex_new_bang1(CLASS_OF(self), other), self);
1164
1165 rb_raise(rb_eTypeError, "%"PRIsVALUE" can't be coerced into %"PRIsVALUE,
1166 rb_obj_class(other), rb_obj_class(self));
1167 return Qnil;
1168}
1169
1170/*
1171 * call-seq:
1172 * cmp.abs -> real
1173 * cmp.magnitude -> real
1174 *
1175 * Returns the absolute part of its polar form.
1176 *
1177 * Complex(-1).abs #=> 1
1178 * Complex(3.0, -4.0).abs #=> 5.0
1179 */
1180 VALUE
1181rb_complex_abs(VALUE self)
1182{
1183 get_dat1(self);
1184
1185 if (f_zero_p(dat->real)) {
1186 VALUE a = f_abs(dat->imag);
1187 if (RB_FLOAT_TYPE_P(dat->real) && !RB_FLOAT_TYPE_P(dat->imag))
1188 a = f_to_f(a);
1189 return a;
1190 }
1191 if (f_zero_p(dat->imag)) {
1192 VALUE a = f_abs(dat->real);
1193 if (!RB_FLOAT_TYPE_P(dat->real) && RB_FLOAT_TYPE_P(dat->imag))
1194 a = f_to_f(a);
1195 return a;
1196 }
1197 return rb_math_hypot(dat->real, dat->imag);
1198}
1199
1200/*
1201 * call-seq:
1202 * cmp.abs2 -> real
1203 *
1204 * Returns square of the absolute value.
1205 *
1206 * Complex(-1).abs2 #=> 1
1207 * Complex(3.0, -4.0).abs2 #=> 25.0
1208 */
1209static VALUE
1210nucomp_abs2(VALUE self)
1211{
1212 get_dat1(self);
1213 return f_add(f_mul(dat->real, dat->real),
1214 f_mul(dat->imag, dat->imag));
1215}
1216
1217/*
1218 * call-seq:
1219 * cmp.arg -> float
1220 * cmp.angle -> float
1221 * cmp.phase -> float
1222 *
1223 * Returns the angle part of its polar form.
1224 *
1225 * Complex.polar(3, Math::PI/2).arg #=> 1.5707963267948966
1226 */
1227 VALUE
1228rb_complex_arg(VALUE self)
1229{
1230 get_dat1(self);
1231 return rb_math_atan2(dat->imag, dat->real);
1232}
1233
1234/*
1235 * call-seq:
1236 * cmp.rect -> array
1237 * cmp.rectangular -> array
1238 *
1239 * Returns an array; [cmp.real, cmp.imag].
1240 *
1241 * Complex(1, 2).rectangular #=> [1, 2]
1242 */
1243static VALUE
1244nucomp_rect(VALUE self)
1245{
1246 get_dat1(self);
1247 return rb_assoc_new(dat->real, dat->imag);
1248}
1249
1250/*
1251 * call-seq:
1252 * cmp.polar -> array
1253 *
1254 * Returns an array; [cmp.abs, cmp.arg].
1255 *
1256 * Complex(1, 2).polar #=> [2.23606797749979, 1.1071487177940904]
1257 */
1258static VALUE
1259nucomp_polar(VALUE self)
1260{
1261 return rb_assoc_new(f_abs(self), f_arg(self));
1262}
1263
1264/*
1265 * call-seq:
1266 * cmp.conj -> complex
1267 * cmp.conjugate -> complex
1268 *
1269 * Returns the complex conjugate.
1270 *
1271 * Complex(1, 2).conjugate #=> (1-2i)
1272 */
1273 VALUE
1274rb_complex_conjugate(VALUE self)
1275{
1276 get_dat1(self);
1277 return f_complex_new2(CLASS_OF(self), dat->real, f_negate(dat->imag));
1278}
1279
1280/*
1281 * call-seq:
1282 * Complex(1).real? -> false
1283 * Complex(1, 2).real? -> false
1284 *
1285 * Returns false, even if the complex number has no imaginary part.
1286 */
1287static VALUE
1288nucomp_real_p_m(VALUE self)
1289{
1290 return Qfalse;
1291}
1292
1293/*
1294 * call-seq:
1295 * cmp.denominator -> integer
1296 *
1297 * Returns the denominator (lcm of both denominator - real and imag).
1298 *
1299 * See numerator.
1300 */
1301static VALUE
1302nucomp_denominator(VALUE self)
1303{
1304 get_dat1(self);
1305 return rb_lcm(f_denominator(dat->real), f_denominator(dat->imag));
1306}
1307
1308/*
1309 * call-seq:
1310 * cmp.numerator -> numeric
1311 *
1312 * Returns the numerator.
1313 *
1314 * 1 2 3+4i <- numerator
1315 * - + -i -> ----
1316 * 2 3 6 <- denominator
1317 *
1318 * c = Complex('1/2+2/3i') #=> ((1/2)+(2/3)*i)
1319 * n = c.numerator #=> (3+4i)
1320 * d = c.denominator #=> 6
1321 * n / d #=> ((1/2)+(2/3)*i)
1322 * Complex(Rational(n.real, d), Rational(n.imag, d))
1323 * #=> ((1/2)+(2/3)*i)
1324 * See denominator.
1325 */
1326static VALUE
1327nucomp_numerator(VALUE self)
1328{
1329 VALUE cd;
1330
1331 get_dat1(self);
1332
1333 cd = nucomp_denominator(self);
1334 return f_complex_new2(CLASS_OF(self),
1335 f_mul(f_numerator(dat->real),
1336 f_div(cd, f_denominator(dat->real))),
1337 f_mul(f_numerator(dat->imag),
1338 f_div(cd, f_denominator(dat->imag))));
1339}
1340
1341/* :nodoc: */
1342st_index_t
1343rb_complex_hash(VALUE self)
1344{
1345 st_index_t v, h[2];
1346 VALUE n;
1347
1348 get_dat1(self);
1349 n = rb_hash(dat->real);
1350 h[0] = NUM2LONG(n);
1351 n = rb_hash(dat->imag);
1352 h[1] = NUM2LONG(n);
1353 v = rb_memhash(h, sizeof(h));
1354 return v;
1355}
1356
1357static VALUE
1358nucomp_hash(VALUE self)
1359{
1360 return ST2FIX(rb_complex_hash(self));
1361}
1362
1363/* :nodoc: */
1364static VALUE
1365nucomp_eql_p(VALUE self, VALUE other)
1366{
1367 if (RB_TYPE_P(other, T_COMPLEX)) {
1368 get_dat2(self, other);
1369
1370 return RBOOL((CLASS_OF(adat->real) == CLASS_OF(bdat->real)) &&
1371 (CLASS_OF(adat->imag) == CLASS_OF(bdat->imag)) &&
1372 f_eqeq_p(self, other));
1373
1374 }
1375 return Qfalse;
1376}
1377
1378inline static int
1379f_signbit(VALUE x)
1380{
1381 if (RB_FLOAT_TYPE_P(x)) {
1382 double f = RFLOAT_VALUE(x);
1383 return !isnan(f) && signbit(f);
1384 }
1385 return f_negative_p(x);
1386}
1387
1388inline static int
1389f_tpositive_p(VALUE x)
1390{
1391 return !f_signbit(x);
1392}
1393
1394static VALUE
1395f_format(VALUE self, VALUE (*func)(VALUE))
1396{
1397 VALUE s;
1398 int impos;
1399
1400 get_dat1(self);
1401
1402 impos = f_tpositive_p(dat->imag);
1403
1404 s = (*func)(dat->real);
1405 rb_str_cat2(s, !impos ? "-" : "+");
1406
1407 rb_str_concat(s, (*func)(f_abs(dat->imag)));
1408 if (!rb_isdigit(RSTRING_PTR(s)[RSTRING_LEN(s) - 1]))
1409 rb_str_cat2(s, "*");
1410 rb_str_cat2(s, "i");
1411
1412 return s;
1413}
1414
1415/*
1416 * call-seq:
1417 * cmp.to_s -> string
1418 *
1419 * Returns the value as a string.
1420 *
1421 * Complex(2).to_s #=> "2+0i"
1422 * Complex('-8/6').to_s #=> "-4/3+0i"
1423 * Complex('1/2i').to_s #=> "0+1/2i"
1424 * Complex(0, Float::INFINITY).to_s #=> "0+Infinity*i"
1425 * Complex(Float::NAN, Float::NAN).to_s #=> "NaN+NaN*i"
1426 */
1427static VALUE
1428nucomp_to_s(VALUE self)
1429{
1430 return f_format(self, rb_String);
1431}
1432
1433/*
1434 * call-seq:
1435 * cmp.inspect -> string
1436 *
1437 * Returns the value as a string for inspection.
1438 *
1439 * Complex(2).inspect #=> "(2+0i)"
1440 * Complex('-8/6').inspect #=> "((-4/3)+0i)"
1441 * Complex('1/2i').inspect #=> "(0+(1/2)*i)"
1442 * Complex(0, Float::INFINITY).inspect #=> "(0+Infinity*i)"
1443 * Complex(Float::NAN, Float::NAN).inspect #=> "(NaN+NaN*i)"
1444 */
1445static VALUE
1446nucomp_inspect(VALUE self)
1447{
1448 VALUE s;
1449
1450 s = rb_usascii_str_new2("(");
1451 rb_str_concat(s, f_format(self, rb_inspect));
1452 rb_str_cat2(s, ")");
1453
1454 return s;
1455}
1456
1457#define FINITE_TYPE_P(v) (RB_INTEGER_TYPE_P(v) || RB_TYPE_P(v, T_RATIONAL))
1458
1459/*
1460 * call-seq:
1461 * cmp.finite? -> true or false
1462 *
1463 * Returns +true+ if +cmp+'s real and imaginary parts are both finite numbers,
1464 * otherwise returns +false+.
1465 */
1466static VALUE
1467rb_complex_finite_p(VALUE self)
1468{
1469 get_dat1(self);
1470
1471 return RBOOL(f_finite_p(dat->real) && f_finite_p(dat->imag));
1472}
1473
1474/*
1475 * call-seq:
1476 * cmp.infinite? -> nil or 1
1477 *
1478 * Returns +1+ if +cmp+'s real or imaginary part is an infinite number,
1479 * otherwise returns +nil+.
1480 *
1481 * For example:
1482 *
1483 * (1+1i).infinite? #=> nil
1484 * (Float::INFINITY + 1i).infinite? #=> 1
1485 */
1486static VALUE
1487rb_complex_infinite_p(VALUE self)
1488{
1489 get_dat1(self);
1490
1491 if (!f_infinite_p(dat->real) && !f_infinite_p(dat->imag)) {
1492 return Qnil;
1493 }
1494 return ONE;
1495}
1496
1497/* :nodoc: */
1498static VALUE
1499nucomp_dumper(VALUE self)
1500{
1501 return self;
1502}
1503
1504/* :nodoc: */
1505static VALUE
1506nucomp_loader(VALUE self, VALUE a)
1507{
1508 get_dat1(self);
1509
1510 RCOMPLEX_SET_REAL(dat, rb_ivar_get(a, id_i_real));
1511 RCOMPLEX_SET_IMAG(dat, rb_ivar_get(a, id_i_imag));
1512 OBJ_FREEZE_RAW(self);
1513
1514 return self;
1515}
1516
1517/* :nodoc: */
1518static VALUE
1519nucomp_marshal_dump(VALUE self)
1520{
1521 VALUE a;
1522 get_dat1(self);
1523
1524 a = rb_assoc_new(dat->real, dat->imag);
1525 rb_copy_generic_ivar(a, self);
1526 return a;
1527}
1528
1529/* :nodoc: */
1530static VALUE
1531nucomp_marshal_load(VALUE self, VALUE a)
1532{
1533 Check_Type(a, T_ARRAY);
1534 if (RARRAY_LEN(a) != 2)
1535 rb_raise(rb_eArgError, "marshaled complex must have an array whose length is 2 but %ld", RARRAY_LEN(a));
1536 rb_ivar_set(self, id_i_real, RARRAY_AREF(a, 0));
1537 rb_ivar_set(self, id_i_imag, RARRAY_AREF(a, 1));
1538 return self;
1539}
1540
1541 VALUE
1542rb_complex_raw(VALUE x, VALUE y)
1543{
1544 return nucomp_s_new_internal(rb_cComplex, x, y);
1545}
1546
1547 VALUE
1548rb_complex_new(VALUE x, VALUE y)
1549{
1550 return nucomp_s_canonicalize_internal(rb_cComplex, x, y);
1551}
1552
1553 VALUE
1554rb_complex_new_polar(VALUE x, VALUE y)
1555{
1556 return f_complex_polar(rb_cComplex, x, y);
1557}
1558
1559 VALUE
1560rb_complex_polar(VALUE x, VALUE y)
1561{
1562 return rb_complex_new_polar(x, y);
1563}
1564
1565 VALUE
1566rb_Complex(VALUE x, VALUE y)
1567{
1568 VALUE a[2];
1569 a[0] = x;
1570 a[1] = y;
1571 return nucomp_s_convert(2, a, rb_cComplex);
1572}
1573
1574 VALUE
1575rb_dbl_complex_new(double real, double imag)
1576{
1577 return rb_complex_raw(DBL2NUM(real), DBL2NUM(imag));
1578}
1579
1580/*
1581 * call-seq:
1582 * cmp.to_i -> integer
1583 *
1584 * Returns the value as an integer if possible (the imaginary part
1585 * should be exactly zero).
1586 *
1587 * Complex(1, 0).to_i #=> 1
1588 * Complex(1, 0.0).to_i # RangeError
1589 * Complex(1, 2).to_i # RangeError
1590 */
1591static VALUE
1592nucomp_to_i(VALUE self)
1593{
1594 get_dat1(self);
1595
1596 if (!k_exact_zero_p(dat->imag)) {
1597 rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Integer",
1598 self);
1599 }
1600 return f_to_i(dat->real);
1601}
1602
1603/*
1604 * call-seq:
1605 * cmp.to_f -> float
1606 *
1607 * Returns the value as a float if possible (the imaginary part should
1608 * be exactly zero).
1609 *
1610 * Complex(1, 0).to_f #=> 1.0
1611 * Complex(1, 0.0).to_f # RangeError
1612 * Complex(1, 2).to_f # RangeError
1613 */
1614static VALUE
1615nucomp_to_f(VALUE self)
1616{
1617 get_dat1(self);
1618
1619 if (!k_exact_zero_p(dat->imag)) {
1620 rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Float",
1621 self);
1622 }
1623 return f_to_f(dat->real);
1624}
1625
1626/*
1627 * call-seq:
1628 * cmp.to_r -> rational
1629 *
1630 * Returns the value as a rational if possible (the imaginary part
1631 * should be exactly zero).
1632 *
1633 * Complex(1, 0).to_r #=> (1/1)
1634 * Complex(1, 0.0).to_r # RangeError
1635 * Complex(1, 2).to_r # RangeError
1636 *
1637 * See rationalize.
1638 */
1639static VALUE
1640nucomp_to_r(VALUE self)
1641{
1642 get_dat1(self);
1643
1644 if (!k_exact_zero_p(dat->imag)) {
1645 rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Rational",
1646 self);
1647 }
1648 return f_to_r(dat->real);
1649}
1650
1651/*
1652 * call-seq:
1653 * cmp.rationalize([eps]) -> rational
1654 *
1655 * Returns the value as a rational if possible (the imaginary part
1656 * should be exactly zero).
1657 *
1658 * Complex(1.0/3, 0).rationalize #=> (1/3)
1659 * Complex(1, 0.0).rationalize # RangeError
1660 * Complex(1, 2).rationalize # RangeError
1661 *
1662 * See to_r.
1663 */
1664static VALUE
1665nucomp_rationalize(int argc, VALUE *argv, VALUE self)
1666{
1667 get_dat1(self);
1668
1669 rb_check_arity(argc, 0, 1);
1670
1671 if (!k_exact_zero_p(dat->imag)) {
1672 rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Rational",
1673 self);
1674 }
1675 return rb_funcallv(dat->real, id_rationalize, argc, argv);
1676}
1677
1678/*
1679 * call-seq:
1680 * complex.to_c -> self
1681 *
1682 * Returns self.
1683 *
1684 * Complex(2).to_c #=> (2+0i)
1685 * Complex(-8, 6).to_c #=> (-8+6i)
1686 */
1687static VALUE
1688nucomp_to_c(VALUE self)
1689{
1690 return self;
1691}
1692
1693/*
1694 * call-seq:
1695 * nil.to_c -> (0+0i)
1696 *
1697 * Returns zero as a complex.
1698 */
1699static VALUE
1700nilclass_to_c(VALUE self)
1701{
1702 return rb_complex_new1(INT2FIX(0));
1703}
1704
1705/*
1706 * call-seq:
1707 * num.to_c -> complex
1708 *
1709 * Returns the value as a complex.
1710 */
1711static VALUE
1712numeric_to_c(VALUE self)
1713{
1714 return rb_complex_new1(self);
1715}
1716
1717inline static int
1718issign(int c)
1719{
1720 return (c == '-' || c == '+');
1721}
1722
1723static int
1724read_sign(const char **s,
1725 char **b)
1726{
1727 int sign = '?';
1728
1729 if (issign(**s)) {
1730 sign = **b = **s;
1731 (*s)++;
1732 (*b)++;
1733 }
1734 return sign;
1735}
1736
1737inline static int
1738isdecimal(int c)
1739{
1740 return isdigit((unsigned char)c);
1741}
1742
1743static int
1744read_digits(const char **s, int strict,
1745 char **b)
1746{
1747 int us = 1;
1748
1749 if (!isdecimal(**s))
1750 return 0;
1751
1752 while (isdecimal(**s) || **s == '_') {
1753 if (**s == '_') {
1754 if (us) {
1755 if (strict) return 0;
1756 break;
1757 }
1758 us = 1;
1759 }
1760 else {
1761 **b = **s;
1762 (*b)++;
1763 us = 0;
1764 }
1765 (*s)++;
1766 }
1767 if (us)
1768 do {
1769 (*s)--;
1770 } while (**s == '_');
1771 return 1;
1772}
1773
1774inline static int
1775islettere(int c)
1776{
1777 return (c == 'e' || c == 'E');
1778}
1779
1780static int
1781read_num(const char **s, int strict,
1782 char **b)
1783{
1784 if (**s != '.') {
1785 if (!read_digits(s, strict, b))
1786 return 0;
1787 }
1788
1789 if (**s == '.') {
1790 **b = **s;
1791 (*s)++;
1792 (*b)++;
1793 if (!read_digits(s, strict, b)) {
1794 (*b)--;
1795 return 0;
1796 }
1797 }
1798
1799 if (islettere(**s)) {
1800 **b = **s;
1801 (*s)++;
1802 (*b)++;
1803 read_sign(s, b);
1804 if (!read_digits(s, strict, b)) {
1805 (*b)--;
1806 return 0;
1807 }
1808 }
1809 return 1;
1810}
1811
1812inline static int
1813read_den(const char **s, int strict,
1814 char **b)
1815{
1816 if (!read_digits(s, strict, b))
1817 return 0;
1818 return 1;
1819}
1820
1821static int
1822read_rat_nos(const char **s, int strict,
1823 char **b)
1824{
1825 if (!read_num(s, strict, b))
1826 return 0;
1827 if (**s == '/') {
1828 **b = **s;
1829 (*s)++;
1830 (*b)++;
1831 if (!read_den(s, strict, b)) {
1832 (*b)--;
1833 return 0;
1834 }
1835 }
1836 return 1;
1837}
1838
1839static int
1840read_rat(const char **s, int strict,
1841 char **b)
1842{
1843 read_sign(s, b);
1844 if (!read_rat_nos(s, strict, b))
1845 return 0;
1846 return 1;
1847}
1848
1849inline static int
1850isimagunit(int c)
1851{
1852 return (c == 'i' || c == 'I' ||
1853 c == 'j' || c == 'J');
1854}
1855
1856static VALUE
1857str2num(char *s)
1858{
1859 if (strchr(s, '/'))
1860 return rb_cstr_to_rat(s, 0);
1861 if (strpbrk(s, ".eE"))
1862 return DBL2NUM(rb_cstr_to_dbl(s, 0));
1863 return rb_cstr_to_inum(s, 10, 0);
1864}
1865
1866static int
1867read_comp(const char **s, int strict,
1868 VALUE *ret, char **b)
1869{
1870 char *bb;
1871 int sign;
1872 VALUE num, num2;
1873
1874 bb = *b;
1875
1876 sign = read_sign(s, b);
1877
1878 if (isimagunit(**s)) {
1879 (*s)++;
1880 num = INT2FIX((sign == '-') ? -1 : + 1);
1881 *ret = rb_complex_new2(ZERO, num);
1882 return 1; /* e.g. "i" */
1883 }
1884
1885 if (!read_rat_nos(s, strict, b)) {
1886 **b = '\0';
1887 num = str2num(bb);
1888 *ret = rb_complex_new2(num, ZERO);
1889 return 0; /* e.g. "-" */
1890 }
1891 **b = '\0';
1892 num = str2num(bb);
1893
1894 if (isimagunit(**s)) {
1895 (*s)++;
1896 *ret = rb_complex_new2(ZERO, num);
1897 return 1; /* e.g. "3i" */
1898 }
1899
1900 if (**s == '@') {
1901 int st;
1902
1903 (*s)++;
1904 bb = *b;
1905 st = read_rat(s, strict, b);
1906 **b = '\0';
1907 if (strlen(bb) < 1 ||
1908 !isdecimal(*(bb + strlen(bb) - 1))) {
1909 *ret = rb_complex_new2(num, ZERO);
1910 return 0; /* e.g. "1@-" */
1911 }
1912 num2 = str2num(bb);
1913 *ret = rb_complex_new_polar(num, num2);
1914 if (!st)
1915 return 0; /* e.g. "1@2." */
1916 else
1917 return 1; /* e.g. "1@2" */
1918 }
1919
1920 if (issign(**s)) {
1921 bb = *b;
1922 sign = read_sign(s, b);
1923 if (isimagunit(**s))
1924 num2 = INT2FIX((sign == '-') ? -1 : + 1);
1925 else {
1926 if (!read_rat_nos(s, strict, b)) {
1927 *ret = rb_complex_new2(num, ZERO);
1928 return 0; /* e.g. "1+xi" */
1929 }
1930 **b = '\0';
1931 num2 = str2num(bb);
1932 }
1933 if (!isimagunit(**s)) {
1934 *ret = rb_complex_new2(num, ZERO);
1935 return 0; /* e.g. "1+3x" */
1936 }
1937 (*s)++;
1938 *ret = rb_complex_new2(num, num2);
1939 return 1; /* e.g. "1+2i" */
1940 }
1941 /* !(@, - or +) */
1942 {
1943 *ret = rb_complex_new2(num, ZERO);
1944 return 1; /* e.g. "3" */
1945 }
1946}
1947
1948inline static void
1949skip_ws(const char **s)
1950{
1951 while (isspace((unsigned char)**s))
1952 (*s)++;
1953}
1954
1955static int
1956parse_comp(const char *s, int strict, VALUE *num)
1957{
1958 char *buf, *b;
1959 VALUE tmp;
1960 int ret = 1;
1961
1962 buf = ALLOCV_N(char, tmp, strlen(s) + 1);
1963 b = buf;
1964
1965 skip_ws(&s);
1966 if (!read_comp(&s, strict, num, &b)) {
1967 ret = 0;
1968 }
1969 else {
1970 skip_ws(&s);
1971
1972 if (strict)
1973 if (*s != '\0')
1974 ret = 0;
1975 }
1976 ALLOCV_END(tmp);
1977
1978 return ret;
1979}
1980
1981static VALUE
1982string_to_c_strict(VALUE self, int raise)
1983{
1984 char *s;
1985 VALUE num;
1986
1987 rb_must_asciicompat(self);
1988
1989 s = RSTRING_PTR(self);
1990
1991 if (!s || memchr(s, '\0', RSTRING_LEN(self))) {
1992 if (!raise) return Qnil;
1993 rb_raise(rb_eArgError, "string contains null byte");
1994 }
1995
1996 if (s && s[RSTRING_LEN(self)]) {
1997 rb_str_modify(self);
1998 s = RSTRING_PTR(self);
1999 s[RSTRING_LEN(self)] = '\0';
2000 }
2001
2002 if (!s)
2003 s = (char *)"";
2004
2005 if (!parse_comp(s, 1, &num)) {
2006 if (!raise) return Qnil;
2007 rb_raise(rb_eArgError, "invalid value for convert(): %+"PRIsVALUE,
2008 self);
2009 }
2010
2011 return num;
2012}
2013
2014/*
2015 * call-seq:
2016 * str.to_c -> complex
2017 *
2018 * Returns a complex which denotes the string form. The parser
2019 * ignores leading whitespaces and trailing garbage. Any digit
2020 * sequences can be separated by an underscore. Returns zero for null
2021 * or garbage string.
2022 *
2023 * '9'.to_c #=> (9+0i)
2024 * '2.5'.to_c #=> (2.5+0i)
2025 * '2.5/1'.to_c #=> ((5/2)+0i)
2026 * '-3/2'.to_c #=> ((-3/2)+0i)
2027 * '-i'.to_c #=> (0-1i)
2028 * '45i'.to_c #=> (0+45i)
2029 * '3-4i'.to_c #=> (3-4i)
2030 * '-4e2-4e-2i'.to_c #=> (-400.0-0.04i)
2031 * '-0.0-0.0i'.to_c #=> (-0.0-0.0i)
2032 * '1/2+3/4i'.to_c #=> ((1/2)+(3/4)*i)
2033 * 'ruby'.to_c #=> (0+0i)
2034 *
2035 * Polar form:
2036 * include Math
2037 * "1.0@0".to_c #=> (1+0.0i)
2038 * "1.0@#{PI/2}".to_c #=> (0.0+1i)
2039 * "1.0@#{PI}".to_c #=> (-1+0.0i)
2040 *
2041 * See Kernel.Complex.
2042 */
2043static VALUE
2044string_to_c(VALUE self)
2045{
2046 char *s;
2047 VALUE num;
2048
2049 rb_must_asciicompat(self);
2050
2051 s = RSTRING_PTR(self);
2052
2053 if (s && s[RSTRING_LEN(self)]) {
2054 rb_str_modify(self);
2055 s = RSTRING_PTR(self);
2056 s[RSTRING_LEN(self)] = '\0';
2057 }
2058
2059 if (!s)
2060 s = (char *)"";
2061
2062 (void)parse_comp(s, 0, &num);
2063
2064 return num;
2065}
2066
2067static VALUE
2068to_complex(VALUE val)
2069{
2070 return rb_convert_type(val, T_COMPLEX, "Complex", "to_c");
2071}
2072
2073static VALUE
2074nucomp_convert(VALUE klass, VALUE a1, VALUE a2, int raise)
2075{
2076 if (NIL_P(a1) || NIL_P(a2)) {
2077 if (!raise) return Qnil;
2078 rb_raise(rb_eTypeError, "can't convert nil into Complex");
2079 }
2080
2081 if (RB_TYPE_P(a1, T_STRING)) {
2082 a1 = string_to_c_strict(a1, raise);
2083 if (NIL_P(a1)) return Qnil;
2084 }
2085
2086 if (RB_TYPE_P(a2, T_STRING)) {
2087 a2 = string_to_c_strict(a2, raise);
2088 if (NIL_P(a2)) return Qnil;
2089 }
2090
2091 if (RB_TYPE_P(a1, T_COMPLEX)) {
2092 {
2093 get_dat1(a1);
2094
2095 if (k_exact_zero_p(dat->imag))
2096 a1 = dat->real;
2097 }
2098 }
2099
2100 if (RB_TYPE_P(a2, T_COMPLEX)) {
2101 {
2102 get_dat1(a2);
2103
2104 if (k_exact_zero_p(dat->imag))
2105 a2 = dat->real;
2106 }
2107 }
2108
2109 if (RB_TYPE_P(a1, T_COMPLEX)) {
2110 if (UNDEF_P(a2) || (k_exact_zero_p(a2)))
2111 return a1;
2112 }
2113
2114 if (UNDEF_P(a2)) {
2115 if (k_numeric_p(a1) && !f_real_p(a1))
2116 return a1;
2117 /* should raise exception for consistency */
2118 if (!k_numeric_p(a1)) {
2119 if (!raise) {
2120 a1 = rb_protect(to_complex, a1, NULL);
2121 rb_set_errinfo(Qnil);
2122 return a1;
2123 }
2124 return to_complex(a1);
2125 }
2126 }
2127 else {
2128 if ((k_numeric_p(a1) && k_numeric_p(a2)) &&
2129 (!f_real_p(a1) || !f_real_p(a2)))
2130 return f_add(a1,
2131 f_mul(a2,
2132 f_complex_new_bang2(rb_cComplex, ZERO, ONE)));
2133 }
2134
2135 {
2136 int argc;
2137 VALUE argv2[2];
2138 argv2[0] = a1;
2139 if (UNDEF_P(a2)) {
2140 argv2[1] = Qnil;
2141 argc = 1;
2142 }
2143 else {
2144 if (!raise && !RB_INTEGER_TYPE_P(a2) && !RB_FLOAT_TYPE_P(a2) && !RB_TYPE_P(a2, T_RATIONAL))
2145 return Qnil;
2146 argv2[1] = a2;
2147 argc = 2;
2148 }
2149 return nucomp_s_new(argc, argv2, klass);
2150 }
2151}
2152
2153static VALUE
2154nucomp_s_convert(int argc, VALUE *argv, VALUE klass)
2155{
2156 VALUE a1, a2;
2157
2158 if (rb_scan_args(argc, argv, "11", &a1, &a2) == 1) {
2159 a2 = Qundef;
2160 }
2161
2162 return nucomp_convert(klass, a1, a2, TRUE);
2163}
2164
2165/*
2166 * call-seq:
2167 * num.abs2 -> real
2168 *
2169 * Returns square of self.
2170 */
2171static VALUE
2172numeric_abs2(VALUE self)
2173{
2174 return f_mul(self, self);
2175}
2176
2177/*
2178 * call-seq:
2179 * num.arg -> 0 or float
2180 * num.angle -> 0 or float
2181 * num.phase -> 0 or float
2182 *
2183 * Returns 0 if the value is positive, pi otherwise.
2184 */
2185static VALUE
2186numeric_arg(VALUE self)
2187{
2188 if (f_positive_p(self))
2189 return INT2FIX(0);
2190 return DBL2NUM(M_PI);
2191}
2192
2193/*
2194 * call-seq:
2195 * num.rect -> array
2196 * num.rectangular -> array
2197 *
2198 * Returns an array; [num, 0].
2199 */
2200static VALUE
2201numeric_rect(VALUE self)
2202{
2203 return rb_assoc_new(self, INT2FIX(0));
2204}
2205
2206/*
2207 * call-seq:
2208 * num.polar -> array
2209 *
2210 * Returns an array; [num.abs, num.arg].
2211 */
2212static VALUE
2213numeric_polar(VALUE self)
2214{
2215 VALUE abs, arg;
2216
2217 if (RB_INTEGER_TYPE_P(self)) {
2218 abs = rb_int_abs(self);
2219 arg = numeric_arg(self);
2220 }
2221 else if (RB_FLOAT_TYPE_P(self)) {
2222 abs = rb_float_abs(self);
2223 arg = float_arg(self);
2224 }
2225 else if (RB_TYPE_P(self, T_RATIONAL)) {
2226 abs = rb_rational_abs(self);
2227 arg = numeric_arg(self);
2228 }
2229 else {
2230 abs = f_abs(self);
2231 arg = f_arg(self);
2232 }
2233 return rb_assoc_new(abs, arg);
2234}
2235
2236/*
2237 * call-seq:
2238 * flo.arg -> 0 or float
2239 * flo.angle -> 0 or float
2240 * flo.phase -> 0 or float
2241 *
2242 * Returns 0 if the value is positive, pi otherwise.
2243 */
2244static VALUE
2245float_arg(VALUE self)
2246{
2247 if (isnan(RFLOAT_VALUE(self)))
2248 return self;
2249 if (f_tpositive_p(self))
2250 return INT2FIX(0);
2251 return rb_const_get(rb_mMath, id_PI);
2252}
2253
2254/*
2255 * A complex number can be represented as a paired real number with
2256 * imaginary unit; a+bi. Where a is real part, b is imaginary part
2257 * and i is imaginary unit. Real a equals complex a+0i
2258 * mathematically.
2259 *
2260 * You can create a \Complex object explicitly with:
2261 *
2262 * - A {complex literal}[rdoc-ref:syntax/literals.rdoc@Complex+Literals].
2263 *
2264 * You can convert certain objects to \Complex objects with:
2265 *
2266 * - \Method #Complex.
2267 *
2268 * Complex object can be created as literal, and also by using
2269 * Kernel#Complex, Complex::rect, Complex::polar or to_c method.
2270 *
2271 * 2+1i #=> (2+1i)
2272 * Complex(1) #=> (1+0i)
2273 * Complex(2, 3) #=> (2+3i)
2274 * Complex.polar(2, 3) #=> (-1.9799849932008908+0.2822400161197344i)
2275 * 3.to_c #=> (3+0i)
2276 *
2277 * You can also create complex object from floating-point numbers or
2278 * strings.
2279 *
2280 * Complex(0.3) #=> (0.3+0i)
2281 * Complex('0.3-0.5i') #=> (0.3-0.5i)
2282 * Complex('2/3+3/4i') #=> ((2/3)+(3/4)*i)
2283 * Complex('1@2') #=> (-0.4161468365471424+0.9092974268256817i)
2284 *
2285 * 0.3.to_c #=> (0.3+0i)
2286 * '0.3-0.5i'.to_c #=> (0.3-0.5i)
2287 * '2/3+3/4i'.to_c #=> ((2/3)+(3/4)*i)
2288 * '1@2'.to_c #=> (-0.4161468365471424+0.9092974268256817i)
2289 *
2290 * A complex object is either an exact or an inexact number.
2291 *
2292 * Complex(1, 1) / 2 #=> ((1/2)+(1/2)*i)
2293 * Complex(1, 1) / 2.0 #=> (0.5+0.5i)
2294 */
2295void
2296Init_Complex(void)
2297{
2298 VALUE compat;
2299 id_abs = rb_intern_const("abs");
2300 id_arg = rb_intern_const("arg");
2301 id_denominator = rb_intern_const("denominator");
2302 id_numerator = rb_intern_const("numerator");
2303 id_real_p = rb_intern_const("real?");
2304 id_i_real = rb_intern_const("@real");
2305 id_i_imag = rb_intern_const("@image"); /* @image, not @imag */
2306 id_finite_p = rb_intern_const("finite?");
2307 id_infinite_p = rb_intern_const("infinite?");
2308 id_rationalize = rb_intern_const("rationalize");
2309 id_PI = rb_intern_const("PI");
2310
2311 rb_cComplex = rb_define_class("Complex", rb_cNumeric);
2312
2313 rb_define_alloc_func(rb_cComplex, nucomp_s_alloc);
2314 rb_undef_method(CLASS_OF(rb_cComplex), "allocate");
2315
2316 rb_undef_method(CLASS_OF(rb_cComplex), "new");
2317
2318 rb_define_singleton_method(rb_cComplex, "rectangular", nucomp_s_new, -1);
2319 rb_define_singleton_method(rb_cComplex, "rect", nucomp_s_new, -1);
2320 rb_define_singleton_method(rb_cComplex, "polar", nucomp_s_polar, -1);
2321
2322 rb_define_global_function("Complex", nucomp_f_complex, -1);
2323
2324 rb_undef_methods_from(rb_cComplex, RCLASS_ORIGIN(rb_mComparable));
2325 rb_undef_method(rb_cComplex, "%");
2326 rb_undef_method(rb_cComplex, "div");
2327 rb_undef_method(rb_cComplex, "divmod");
2328 rb_undef_method(rb_cComplex, "floor");
2329 rb_undef_method(rb_cComplex, "ceil");
2330 rb_undef_method(rb_cComplex, "modulo");
2331 rb_undef_method(rb_cComplex, "remainder");
2332 rb_undef_method(rb_cComplex, "round");
2333 rb_undef_method(rb_cComplex, "step");
2334 rb_undef_method(rb_cComplex, "truncate");
2335 rb_undef_method(rb_cComplex, "i");
2336
2337 rb_define_method(rb_cComplex, "real", rb_complex_real, 0);
2338 rb_define_method(rb_cComplex, "imaginary", rb_complex_imag, 0);
2339 rb_define_method(rb_cComplex, "imag", rb_complex_imag, 0);
2340
2341 rb_define_method(rb_cComplex, "-@", rb_complex_uminus, 0);
2342 rb_define_method(rb_cComplex, "+", rb_complex_plus, 1);
2343 rb_define_method(rb_cComplex, "-", rb_complex_minus, 1);
2344 rb_define_method(rb_cComplex, "*", rb_complex_mul, 1);
2345 rb_define_method(rb_cComplex, "/", rb_complex_div, 1);
2346 rb_define_method(rb_cComplex, "quo", nucomp_quo, 1);
2347 rb_define_method(rb_cComplex, "fdiv", nucomp_fdiv, 1);
2348 rb_define_method(rb_cComplex, "**", rb_complex_pow, 1);
2349
2350 rb_define_method(rb_cComplex, "==", nucomp_eqeq_p, 1);
2351 rb_define_method(rb_cComplex, "<=>", nucomp_cmp, 1);
2352 rb_define_method(rb_cComplex, "coerce", nucomp_coerce, 1);
2353
2354 rb_define_method(rb_cComplex, "abs", rb_complex_abs, 0);
2355 rb_define_method(rb_cComplex, "magnitude", rb_complex_abs, 0);
2356 rb_define_method(rb_cComplex, "abs2", nucomp_abs2, 0);
2357 rb_define_method(rb_cComplex, "arg", rb_complex_arg, 0);
2358 rb_define_method(rb_cComplex, "angle", rb_complex_arg, 0);
2359 rb_define_method(rb_cComplex, "phase", rb_complex_arg, 0);
2360 rb_define_method(rb_cComplex, "rectangular", nucomp_rect, 0);
2361 rb_define_method(rb_cComplex, "rect", nucomp_rect, 0);
2362 rb_define_method(rb_cComplex, "polar", nucomp_polar, 0);
2363 rb_define_method(rb_cComplex, "conjugate", rb_complex_conjugate, 0);
2364 rb_define_method(rb_cComplex, "conj", rb_complex_conjugate, 0);
2365
2366 rb_define_method(rb_cComplex, "real?", nucomp_real_p_m, 0);
2367
2368 rb_define_method(rb_cComplex, "numerator", nucomp_numerator, 0);
2369 rb_define_method(rb_cComplex, "denominator", nucomp_denominator, 0);
2370
2371 rb_define_method(rb_cComplex, "hash", nucomp_hash, 0);
2372 rb_define_method(rb_cComplex, "eql?", nucomp_eql_p, 1);
2373
2374 rb_define_method(rb_cComplex, "to_s", nucomp_to_s, 0);
2375 rb_define_method(rb_cComplex, "inspect", nucomp_inspect, 0);
2376
2377 rb_undef_method(rb_cComplex, "positive?");
2378 rb_undef_method(rb_cComplex, "negative?");
2379
2380 rb_define_method(rb_cComplex, "finite?", rb_complex_finite_p, 0);
2381 rb_define_method(rb_cComplex, "infinite?", rb_complex_infinite_p, 0);
2382
2383 rb_define_private_method(rb_cComplex, "marshal_dump", nucomp_marshal_dump, 0);
2384 /* :nodoc: */
2385 compat = rb_define_class_under(rb_cComplex, "compatible", rb_cObject);
2386 rb_define_private_method(compat, "marshal_load", nucomp_marshal_load, 1);
2387 rb_marshal_define_compat(rb_cComplex, compat, nucomp_dumper, nucomp_loader);
2388
2389 rb_define_method(rb_cComplex, "to_i", nucomp_to_i, 0);
2390 rb_define_method(rb_cComplex, "to_f", nucomp_to_f, 0);
2391 rb_define_method(rb_cComplex, "to_r", nucomp_to_r, 0);
2392 rb_define_method(rb_cComplex, "rationalize", nucomp_rationalize, -1);
2393 rb_define_method(rb_cComplex, "to_c", nucomp_to_c, 0);
2394 rb_define_method(rb_cNilClass, "to_c", nilclass_to_c, 0);
2395 rb_define_method(rb_cNumeric, "to_c", numeric_to_c, 0);
2396
2397 rb_define_method(rb_cString, "to_c", string_to_c, 0);
2398
2399 rb_define_private_method(CLASS_OF(rb_cComplex), "convert", nucomp_s_convert, -1);
2400
2401 rb_define_method(rb_cNumeric, "abs2", numeric_abs2, 0);
2402 rb_define_method(rb_cNumeric, "arg", numeric_arg, 0);
2403 rb_define_method(rb_cNumeric, "angle", numeric_arg, 0);
2404 rb_define_method(rb_cNumeric, "phase", numeric_arg, 0);
2405 rb_define_method(rb_cNumeric, "rectangular", numeric_rect, 0);
2406 rb_define_method(rb_cNumeric, "rect", numeric_rect, 0);
2407 rb_define_method(rb_cNumeric, "polar", numeric_polar, 0);
2408
2409 rb_define_method(rb_cFloat, "arg", float_arg, 0);
2410 rb_define_method(rb_cFloat, "angle", float_arg, 0);
2411 rb_define_method(rb_cFloat, "phase", float_arg, 0);
2412
2413 /*
2414 * The imaginary unit.
2415 */
2416 rb_define_const(rb_cComplex, "I",
2417 f_complex_new_bang2(rb_cComplex, ZERO, ONE));
2418
2419#if !USE_FLONUM
2420 rb_gc_register_mark_object(RFLOAT_0 = DBL2NUM(0.0));
2421#endif
2422
2423 rb_provide("complex.so"); /* for backward compatibility */
2424}
rb_isdigit
static int rb_isdigit(int c)
Our own locale-insensitive version of isdigit(3).
Definition ctype.h:302
rb_define_method
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition cxxanyargs.hpp:670
rb_define_singleton_method
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
Definition cxxanyargs.hpp:685
rb_define_private_method
#define rb_define_private_method(klass, mid, func, arity)
Defines klass#mid and makes it private.
Definition cxxanyargs.hpp:677
rb_define_global_function
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
Definition cxxanyargs.hpp:695
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:923
rb_define_class_under
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:955
rb_undef_method
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
Definition class.c:2113
rb_scan_args
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:2579
T_COMPLEX
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
Definition value_type.h:59
NEWOBJ_OF
#define NEWOBJ_OF
Old name of RB_NEWOBJ_OF.
Definition newobj.h:61
RB_INTEGER_TYPE_P
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
RFLOAT_VALUE
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
T_STRING
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
Qundef
#define Qundef
Old name of RUBY_Qundef.
Definition special_consts.h:62
INT2FIX
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
rb_str_cat2
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1683
OBJ_FREEZE_RAW
#define OBJ_FREEZE_RAW
Old name of RB_OBJ_FREEZE_RAW.
Definition fl_type.h:144
CLASS_OF
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:203
LONG2FIX
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
T_RATIONAL
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition value_type.h:76
NUM2DBL
#define NUM2DBL
Old name of rb_num2dbl.
Definition double.h:27
rb_complex_polar
VALUE rb_complex_polar(VALUE x, VALUE y)
Old name of rb_complex_new_polar.
Definition complex.c:1560
rb_usascii_str_new2
#define rb_usascii_str_new2
Old name of rb_usascii_str_new_cstr.
Definition string.h:1680
FLONUM_P
#define FLONUM_P
Old name of RB_FLONUM_P.
Definition special_consts.h:67
ST2FIX
#define ST2FIX
Old name of RB_ST2FIX.
Definition st_data_t.h:33
Qnil
#define Qnil
Old name of RUBY_Qnil.
Definition special_consts.h:60
Qfalse
#define Qfalse
Old name of RUBY_Qfalse.
Definition special_consts.h:59
FIX2LONG
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
T_ARRAY
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
NIL_P
#define NIL_P
Old name of RB_NIL_P.
Definition special_consts.h:55
ALLOCV_N
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:399
FL_WB_PROTECTED
#define FL_WB_PROTECTED
Old name of RUBY_FL_WB_PROTECTED.
Definition fl_type.h:59
DBL2NUM
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
NUM2LONG
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
FIXNUM_P
#define FIXNUM_P
Old name of RB_FIXNUM_P.
Definition special_consts.h:53
ALLOCV_END
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:400
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
Definition error.c:3150
rb_set_errinfo
void rb_set_errinfo(VALUE err)
Sets the current exception ($!) to the given value.
Definition eval.c:1884
rb_eRangeError
VALUE rb_eRangeError
RangeError exception.
Definition error.c:1095
rb_eTypeError
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1091
rb_warn
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports always regardless of runtime -W flag.
Definition error.c:411
rb_eArgError
VALUE rb_eArgError
ArgumentError exception.
Definition error.c:1092
rb_cRational
VALUE rb_cRational
Rational class.
Definition rational.c:47
rb_convert_type
VALUE rb_convert_type(VALUE val, int type, const char *name, const char *mid)
Converts an object into another type.
Definition object.c:2935
rb_cComplex
VALUE rb_cComplex
Complex class.
Definition complex.c:38
rb_mMath
VALUE rb_mMath
Math module.
Definition math.c:29
rb_cInteger
VALUE rb_cInteger
Module class.
Definition numeric.c:192
rb_cNilClass
VALUE rb_cNilClass
NilClass class.
Definition object.c:57
rb_str_to_dbl
double rb_str_to_dbl(VALUE str, int mode)
Identical to rb_cstr_to_dbl(), except it accepts a Ruby's string instead of C's.
Definition object.c:3417
rb_cNumeric
VALUE rb_cNumeric
Numeric class.
Definition numeric.c:190
rb_obj_class
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:191
rb_inspect
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:601
rb_equal
VALUE rb_equal(VALUE lhs, VALUE rhs)
This function is an optimised version of calling #==.
Definition object.c:123
rb_obj_is_kind_of
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Definition object.c:788
rb_cstr_to_dbl
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:3376
rb_mComparable
VALUE rb_mComparable
Comparable module.
Definition compar.c:19
rb_cFloat
VALUE rb_cFloat
Float class.
Definition numeric.c:191
rb_String
VALUE rb_String(VALUE val)
This is the logic behind Kernel#String.
Definition object.c:3656
rb_cString
VALUE rb_cString
String class.
Definition string.c:79
rb_funcall
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1102
rb_complex_new2
#define rb_complex_new2(x, y)
Just another name of rb_complex_new.
Definition complex.h:77
rb_complex_new1
#define rb_complex_new1(x)
Shorthand of x+0i.
Definition complex.h:74
rb_check_arity
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:280
rb_provide
void rb_provide(const char *feature)
Declares that the given feature is already provided by someone else.
Definition load.c:685
rb_num_coerce_cmp
VALUE rb_num_coerce_cmp(VALUE lhs, VALUE rhs, ID op)
Identical to rb_num_coerce_bin(), except for return values.
Definition numeric.c:478
rb_num_coerce_bin
VALUE rb_num_coerce_bin(VALUE lhs, VALUE rhs, ID op)
Coerced binary operation.
Definition numeric.c:471
rb_memhash
st_index_t rb_memhash(const void *ptr, long len)
This is a universal hash function.
Definition random.c:1741
rb_str_modify
void rb_str_modify(VALUE str)
Declares that the string is about to be modified.
Definition string.c:2437
rb_must_asciicompat
void rb_must_asciicompat(VALUE obj)
Asserts that the given string's encoding is (Ruby's definition of) ASCII compatible.
Definition string.c:2489
rb_str_concat
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:3453
rb_const_get
VALUE rb_const_get(VALUE space, ID name)
Identical to rb_const_defined(), except it returns the actual defined value.
Definition variable.c:2896
rb_ivar_set
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:1606
rb_ivar_get
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:1218
rb_define_alloc_func
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
rb_intern_const
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:276
rb_define_const
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
Definition variable.c:3440
rb_marshal_define_compat
void rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE(*dumper)(VALUE), VALUE(*loader)(VALUE, VALUE))
Marshal format compatibility layer.
Definition marshal.c:150
rb_copy_generic_ivar
void rb_copy_generic_ivar(VALUE clone, VALUE obj)
Copies the list of instance variables.
Definition variable.c:1740
RARRAY_LEN
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:68
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition rarray.h:583
RGENGC_WB_PROTECTED_COMPLEX
#define RGENGC_WB_PROTECTED_COMPLEX
This is a compile-time flag to enable/disable write barrier for struct RComplex.
Definition rgengc.h:162
RSTRING_LEN
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
Definition rstring.h:484
RSTRING_PTR
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
Definition rstring.h:498
RTEST
#define RTEST
This is an old name of RB_TEST.
Definition special_consts.h:51
RComplex
Internal header for Complex.
Definition complex.h:13
SIGNED_VALUE
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
ID
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
VALUE
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
RB_FLOAT_TYPE_P
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:263
Check_Type
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
RB_TYPE_P
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