Ruby 4.1.0dev (2026-08-15 revision cfb2ed7c723c5435f630fd70897273db032b0bcc)
complex.c (cfb2ed7c723c5435f630fd70897273db032b0bcc)
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/error.h"
24#include "internal/math.h"
25#include "internal/numeric.h"
26#include "internal/object.h"
27#include "internal/rational.h"
28#include "internal/string.h"
29#include "ruby_assert.h"
30
31#define ZERO INT2FIX(0)
32#define ONE INT2FIX(1)
33#define TWO INT2FIX(2)
34#if USE_FLONUM
35#define RFLOAT_0 DBL2NUM(0)
36#else
37static VALUE RFLOAT_0;
38#endif
39
41
42static ID id_abs, id_arg,
43 id_real_p, id_i_real, id_i_imag,
44 id_finite_p, id_infinite_p, id_rationalize,
45 id_PI;
46#define id_to_i idTo_i
47#define id_to_r idTo_r
48#define id_negate idUMinus
49#define id_expt idPow
50#define id_to_f idTo_f
51#define id_quo idQuo
52#define id_fdiv idFdiv
53
54#define PRESERVE_SIGNEDZERO
55
56inline static VALUE
57f_add(VALUE x, VALUE y)
58{
59 if (RB_INTEGER_TYPE_P(x) &&
61 if (FIXNUM_ZERO_P(x))
62 return y;
63 if (FIXNUM_ZERO_P(y))
64 return x;
65 return rb_int_plus(x, y);
66 }
67 else if (RB_FLOAT_TYPE_P(x) &&
68 LIKELY(rb_method_basic_definition_p(rb_cFloat, idPLUS))) {
69 if (FIXNUM_ZERO_P(y))
70 return x;
71 return rb_float_plus(x, y);
72 }
73 else if (RB_TYPE_P(x, T_RATIONAL) &&
75 if (FIXNUM_ZERO_P(y))
76 return x;
77 return rb_rational_plus(x, y);
78 }
79
80 return rb_funcall(x, '+', 1, y);
81}
82
83inline static VALUE
84f_div(VALUE x, VALUE y)
85{
86 if (FIXNUM_P(y) && FIX2LONG(y) == 1)
87 return x;
88 return rb_funcall(x, '/', 1, y);
89}
90
91inline static int
92f_gt_p(VALUE x, VALUE y)
93{
94 if (RB_INTEGER_TYPE_P(x)) {
95 if (FIXNUM_P(x) && FIXNUM_P(y))
96 return (SIGNED_VALUE)x > (SIGNED_VALUE)y;
97 return RTEST(rb_int_gt(x, y));
98 }
99 else if (RB_FLOAT_TYPE_P(x))
100 return RTEST(rb_float_gt(x, y));
101 else if (RB_TYPE_P(x, T_RATIONAL)) {
102 int const cmp = rb_cmpint(rb_rational_cmp(x, y), x, y);
103 return cmp > 0;
104 }
105 return RTEST(rb_funcall(x, '>', 1, y));
106}
107
108inline static VALUE
109f_mul(VALUE x, VALUE y)
110{
111 if (RB_INTEGER_TYPE_P(x) &&
112 LIKELY(rb_method_basic_definition_p(rb_cInteger, idMULT))) {
113 if (FIXNUM_ZERO_P(y))
114 return ZERO;
115 if (FIXNUM_ZERO_P(x) && RB_INTEGER_TYPE_P(y))
116 return ZERO;
117 if (x == ONE) return y;
118 if (y == ONE) return x;
119 return rb_int_mul(x, y);
120 }
121 else if (RB_FLOAT_TYPE_P(x) &&
122 LIKELY(rb_method_basic_definition_p(rb_cFloat, idMULT))) {
123 if (y == ONE) return x;
124 return rb_float_mul(x, y);
125 }
126 else if (RB_TYPE_P(x, T_RATIONAL) &&
128 if (y == ONE) return x;
129 return rb_rational_mul(x, y);
130 }
131 else if (LIKELY(rb_method_basic_definition_p(CLASS_OF(x), idMULT))) {
132 if (y == ONE) return x;
133 }
134 return rb_funcall(x, '*', 1, y);
135}
136
137inline static VALUE
138f_sub(VALUE x, VALUE y)
139{
140 if (FIXNUM_ZERO_P(y) &&
141 LIKELY(rb_method_basic_definition_p(CLASS_OF(x), idMINUS))) {
142 return x;
143 }
144 return rb_funcall(x, '-', 1, y);
145}
146
147inline static VALUE
148f_abs(VALUE x)
149{
150 if (RB_INTEGER_TYPE_P(x)) {
151 return rb_int_abs(x);
152 }
153 else if (RB_FLOAT_TYPE_P(x)) {
154 return rb_float_abs(x);
155 }
156 else if (RB_TYPE_P(x, T_RATIONAL)) {
157 return rb_rational_abs(x);
158 }
159 else if (RB_TYPE_P(x, T_COMPLEX)) {
160 return rb_complex_abs(x);
161 }
162 return rb_funcall(x, id_abs, 0);
163}
164
165static VALUE numeric_arg(VALUE self);
166static VALUE float_arg(VALUE self);
167
168inline static VALUE
169f_arg(VALUE x)
170{
171 if (RB_INTEGER_TYPE_P(x)) {
172 return numeric_arg(x);
173 }
174 else if (RB_FLOAT_TYPE_P(x)) {
175 return float_arg(x);
176 }
177 else if (RB_TYPE_P(x, T_RATIONAL)) {
178 return numeric_arg(x);
179 }
180 else if (RB_TYPE_P(x, T_COMPLEX)) {
181 return rb_complex_arg(x);
182 }
183 return rb_funcall(x, id_arg, 0);
184}
185
186inline static VALUE
187f_numerator(VALUE x)
188{
189 if (RB_TYPE_P(x, T_RATIONAL)) {
190 return RRATIONAL(x)->num;
191 }
192 if (RB_FLOAT_TYPE_P(x)) {
193 return rb_float_numerator(x);
194 }
195 return x;
196}
197
198inline static VALUE
199f_denominator(VALUE x)
200{
201 if (RB_TYPE_P(x, T_RATIONAL)) {
202 return RRATIONAL(x)->den;
203 }
204 if (RB_FLOAT_TYPE_P(x)) {
205 return rb_float_denominator(x);
206 }
207 return INT2FIX(1);
208}
209
210inline static VALUE
211f_negate(VALUE x)
212{
213 if (RB_INTEGER_TYPE_P(x)) {
214 return rb_int_uminus(x);
215 }
216 else if (RB_FLOAT_TYPE_P(x)) {
217 return rb_float_uminus(x);
218 }
219 else if (RB_TYPE_P(x, T_RATIONAL)) {
220 return rb_rational_uminus(x);
221 }
222 else if (RB_TYPE_P(x, T_COMPLEX)) {
223 return rb_complex_uminus(x);
224 }
225 return rb_funcall(x, id_negate, 0);
226}
227
228static bool nucomp_real_p(VALUE self);
229
230static inline bool
231f_real_p(VALUE x)
232{
233 if (RB_INTEGER_TYPE_P(x)) {
234 return true;
235 }
236 else if (RB_FLOAT_TYPE_P(x)) {
237 return true;
238 }
239 else if (RB_TYPE_P(x, T_RATIONAL)) {
240 return true;
241 }
242 else if (RB_TYPE_P(x, T_COMPLEX)) {
243 return nucomp_real_p(x);
244 }
245 return rb_funcall(x, id_real_p, 0);
246}
247
248inline static VALUE
249f_to_i(VALUE x)
250{
251 if (RB_TYPE_P(x, T_STRING))
252 return rb_str_to_inum(x, 10, 0);
253 return rb_funcall(x, id_to_i, 0);
254}
255
256inline static VALUE
257f_to_f(VALUE x)
258{
259 if (RB_TYPE_P(x, T_STRING))
260 return DBL2NUM(rb_str_to_dbl(x, 0));
261 return rb_funcall(x, id_to_f, 0);
262}
263
264inline static int
265f_eqeq_p(VALUE x, VALUE y)
266{
267 if (FIXNUM_P(x) && FIXNUM_P(y))
268 return x == y;
269 else if (RB_FLOAT_TYPE_P(x) || RB_FLOAT_TYPE_P(y))
270 return NUM2DBL(x) == NUM2DBL(y);
271 return (int)rb_equal(x, y);
272}
273
274static VALUE
275f_fdiv(VALUE x, VALUE y)
276{
277 if (RB_INTEGER_TYPE_P(x))
278 return rb_int_fdiv(x, y);
279 if (RB_FLOAT_TYPE_P(x))
280 return rb_float_div(x, y);
281 if (RB_TYPE_P(x, T_RATIONAL))
282 return rb_rational_fdiv(x, y);
283
284 return rb_funcallv(x, id_fdiv, 1, &y);
285}
286
287static VALUE
288f_quo(VALUE x, VALUE y)
289{
290 if (RB_INTEGER_TYPE_P(x))
291 return rb_numeric_quo(x, y);
292 if (RB_FLOAT_TYPE_P(x))
293 return rb_float_div(x, y);
294 if (RB_TYPE_P(x, T_RATIONAL))
295 return rb_numeric_quo(x, y);
296
297 return rb_funcallv(x, id_quo, 1, &y);
298}
299
300inline static int
301f_negative_p(VALUE x)
302{
303 if (RB_INTEGER_TYPE_P(x))
304 return INT_NEGATIVE_P(x);
305 else if (RB_FLOAT_TYPE_P(x))
306 return RFLOAT_VALUE(x) < 0.0;
307 else if (RB_TYPE_P(x, T_RATIONAL))
308 return INT_NEGATIVE_P(RRATIONAL(x)->num);
309 return rb_num_negative_p(x);
310}
311
312#define f_positive_p(x) (!f_negative_p(x))
313
314static inline bool
315always_finite_type_p(VALUE x)
316{
317 if (FIXNUM_P(x)) return true;
318 if (FLONUM_P(x)) return true; /* Infinity can't be a flonum */
319 return (RB_INTEGER_TYPE_P(x) || RB_TYPE_P(x, T_RATIONAL));
320}
321
322inline static int
323f_finite_p(VALUE x)
324{
325 if (always_finite_type_p(x)) {
326 return TRUE;
327 }
328 else if (RB_FLOAT_TYPE_P(x)) {
329 return isfinite(RFLOAT_VALUE(x));
330 }
331 return RTEST(rb_funcallv(x, id_finite_p, 0, 0));
332}
333
334inline static int
335f_infinite_p(VALUE x)
336{
337 if (always_finite_type_p(x)) {
338 return FALSE;
339 }
340 else if (RB_FLOAT_TYPE_P(x)) {
341 return isinf(RFLOAT_VALUE(x));
342 }
343 return RTEST(rb_funcallv(x, id_infinite_p, 0, 0));
344}
345
346inline static int
347f_kind_of_p(VALUE x, VALUE c)
348{
349 return (int)rb_obj_is_kind_of(x, c);
350}
351
352inline static int
353k_numeric_p(VALUE x)
354{
355 return f_kind_of_p(x, rb_cNumeric);
356}
357
358#define k_exact_p(x) (!RB_FLOAT_TYPE_P(x))
359
360#define k_exact_zero_p(x) (k_exact_p(x) && f_zero_p(x))
361
362#define get_dat1(x) \
363 struct RComplex *dat = RCOMPLEX(x)
364
365#define get_dat2(x,y) \
366 struct RComplex *adat = RCOMPLEX(x), *bdat = RCOMPLEX(y)
367
368inline static VALUE
369nucomp_s_new_internal(VALUE klass, VALUE real, VALUE imag)
370{
371 NEWOBJ_OF(obj, struct RComplex, klass, T_COMPLEX, sizeof(struct RComplex));
372
373 RCOMPLEX_SET_REAL(obj, real);
374 RCOMPLEX_SET_IMAG(obj, imag);
375 OBJ_FREEZE((VALUE)obj);
376
377 return (VALUE)obj;
378}
379
380static VALUE
381nucomp_s_alloc(VALUE klass)
382{
383 return nucomp_s_new_internal(klass, ZERO, ZERO);
384}
385
386inline static VALUE
387f_complex_new_bang1(VALUE klass, VALUE x)
388{
390 return nucomp_s_new_internal(klass, x, ZERO);
391}
392
393inline static VALUE
394f_complex_new_bang2(VALUE klass, VALUE x, VALUE y)
395{
398 return nucomp_s_new_internal(klass, x, y);
399}
400
401WARN_UNUSED_RESULT(inline static VALUE nucomp_real_check(VALUE num));
402inline static VALUE
403nucomp_real_check(VALUE num)
404{
405 if (!RB_INTEGER_TYPE_P(num) &&
406 !RB_FLOAT_TYPE_P(num) &&
407 !RB_TYPE_P(num, T_RATIONAL)) {
408 if (RB_TYPE_P(num, T_COMPLEX) && nucomp_real_p(num)) {
409 VALUE real = RCOMPLEX(num)->real;
411 return real;
412 }
413 if (!k_numeric_p(num) || !f_real_p(num))
414 rb_raise(rb_eTypeError, "not a real");
415 }
416 return num;
417}
418
419inline static VALUE
420nucomp_s_canonicalize_internal(VALUE klass, VALUE real, VALUE imag)
421{
422 int complex_r, complex_i;
423 complex_r = RB_TYPE_P(real, T_COMPLEX);
424 complex_i = RB_TYPE_P(imag, T_COMPLEX);
425 if (!complex_r && !complex_i) {
426 return nucomp_s_new_internal(klass, real, imag);
427 }
428 else if (!complex_r) {
429 get_dat1(imag);
430
431 return nucomp_s_new_internal(klass,
432 f_sub(real, dat->imag),
433 f_add(ZERO, dat->real));
434 }
435 else if (!complex_i) {
436 get_dat1(real);
437
438 return nucomp_s_new_internal(klass,
439 dat->real,
440 f_add(dat->imag, imag));
441 }
442 else {
443 get_dat2(real, imag);
444
445 return nucomp_s_new_internal(klass,
446 f_sub(adat->real, bdat->imag),
447 f_add(adat->imag, bdat->real));
448 }
449}
450
451/*
452 * call-seq:
453 * Complex.rect(real, imag = 0) -> complex
454 *
455 * Returns a new \Complex object formed from the arguments,
456 * each of which must be an instance of Numeric,
457 * or an instance of one of its subclasses:
458 * \Complex, Float, Integer, Rational;
459 * see {Rectangular Coordinates}[rdoc-ref:Complex@Rectangular+Coordinates]:
460 *
461 * Complex.rect(3) # => (3+0i)
462 * Complex.rect(3, Math::PI) # => (3+3.141592653589793i)
463 * Complex.rect(-3, -Math::PI) # => (-3-3.141592653589793i)
464 *
465 * \Complex.rectangular is an alias for \Complex.rect.
466 */
467static VALUE
468nucomp_s_new(int argc, VALUE *argv, VALUE klass)
469{
470 VALUE real, imag;
471
472 switch (rb_scan_args(argc, argv, "11", &real, &imag)) {
473 case 1:
474 real = nucomp_real_check(real);
475 imag = ZERO;
476 break;
477 default:
478 real = nucomp_real_check(real);
479 imag = nucomp_real_check(imag);
480 break;
481 }
482
483 return nucomp_s_new_internal(klass, real, imag);
484}
485
486inline static VALUE
487f_complex_new2(VALUE klass, VALUE x, VALUE y)
488{
489 if (RB_TYPE_P(x, T_COMPLEX)) {
490 get_dat1(x);
491 x = dat->real;
492 y = f_add(dat->imag, y);
493 }
494 return nucomp_s_canonicalize_internal(klass, x, y);
495}
496
497static VALUE nucomp_convert(VALUE klass, VALUE a1, VALUE a2, int raise);
498static VALUE nucomp_s_convert(int argc, VALUE *argv, VALUE klass);
499
500/*
501 * call-seq:
502 * Complex(real, imag = 0, exception: true) -> complex or nil
503 * Complex(s, exception: true) -> complex or nil
504 *
505 * Returns a new \Complex object if the arguments are valid;
506 * otherwise raises an exception if +exception+ is +true+;
507 * otherwise returns +nil+.
508 *
509 * With Numeric arguments +real+ and +imag+,
510 * returns <tt>Complex.rect(real, imag)</tt> if the arguments are valid.
511 *
512 * With string argument +s+, returns a new \Complex object if the argument is valid;
513 * the string may have:
514 *
515 * - One or two numeric substrings,
516 * each of which specifies a Complex, Float, Integer, Numeric, or Rational value,
517 * specifying {rectangular coordinates}[rdoc-ref:Complex@Rectangular+Coordinates]:
518 *
519 * - Sign-separated real and imaginary numeric substrings
520 * (with trailing character <tt>'i'</tt>):
521 *
522 * Complex('1+2i') # => (1+2i)
523 * Complex('+1+2i') # => (1+2i)
524 * Complex('+1-2i') # => (1-2i)
525 * Complex('-1+2i') # => (-1+2i)
526 * Complex('-1-2i') # => (-1-2i)
527 *
528 * - Real-only numeric string (without trailing character <tt>'i'</tt>):
529 *
530 * Complex('1') # => (1+0i)
531 * Complex('+1') # => (1+0i)
532 * Complex('-1') # => (-1+0i)
533 *
534 * - Imaginary-only numeric string (with trailing character <tt>'i'</tt>):
535 *
536 * Complex('1i') # => (0+1i)
537 * Complex('+1i') # => (0+1i)
538 * Complex('-1i') # => (0-1i)
539 *
540 * - At-sign separated real and imaginary rational substrings,
541 * each of which specifies a Rational value,
542 * specifying {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates]:
543 *
544 * Complex('1/2@3/4') # => (0.36584443443691045+0.34081938001166706i)
545 * Complex('+1/2@+3/4') # => (0.36584443443691045+0.34081938001166706i)
546 * Complex('+1/2@-3/4') # => (0.36584443443691045-0.34081938001166706i)
547 * Complex('-1/2@+3/4') # => (-0.36584443443691045-0.34081938001166706i)
548 * Complex('-1/2@-3/4') # => (-0.36584443443691045+0.34081938001166706i)
549 *
550 */
551static VALUE
552nucomp_f_complex(int argc, VALUE *argv, VALUE klass)
553{
554 VALUE a1, a2, opts = Qnil;
555 int raise = TRUE;
556
557 if (rb_scan_args(argc, argv, "11:", &a1, &a2, &opts) == 1) {
558 a2 = Qundef;
559 }
560 if (!NIL_P(opts)) {
561 raise = rb_opts_exception_p(opts, raise);
562 }
563 if (argc > 0 && CLASS_OF(a1) == rb_cComplex && UNDEF_P(a2)) {
564 return a1;
565 }
566 return nucomp_convert(rb_cComplex, a1, a2, raise);
567}
568
569#define imp1(n) \
570inline static VALUE \
571m_##n##_bang(VALUE x)\
572{\
573 return rb_math_##n(x);\
574}
575
576imp1(cos)
577imp1(cosh)
578imp1(exp)
579
580static VALUE
581m_log_bang(VALUE x)
582{
583 return rb_math_log(1, &x);
584}
585
586imp1(sin)
587imp1(sinh)
588
589static VALUE
590m_cos(VALUE x)
591{
592 if (!RB_TYPE_P(x, T_COMPLEX))
593 return m_cos_bang(x);
594 {
595 get_dat1(x);
596 return f_complex_new2(rb_cComplex,
597 f_mul(m_cos_bang(dat->real),
598 m_cosh_bang(dat->imag)),
599 f_mul(f_negate(m_sin_bang(dat->real)),
600 m_sinh_bang(dat->imag)));
601 }
602}
603
604static VALUE
605m_sin(VALUE x)
606{
607 if (!RB_TYPE_P(x, T_COMPLEX))
608 return m_sin_bang(x);
609 {
610 get_dat1(x);
611 return f_complex_new2(rb_cComplex,
612 f_mul(m_sin_bang(dat->real),
613 m_cosh_bang(dat->imag)),
614 f_mul(m_cos_bang(dat->real),
615 m_sinh_bang(dat->imag)));
616 }
617}
618
619static VALUE
620f_complex_polar_real(VALUE klass, VALUE x, VALUE y)
621{
622 if (f_zero_p(x) || f_zero_p(y)) {
623 return nucomp_s_new_internal(klass, x, RFLOAT_0);
624 }
625 if (RB_FLOAT_TYPE_P(y)) {
626 const double arg = RFLOAT_VALUE(y);
627 if (arg == M_PI) {
628 x = f_negate(x);
629 y = RFLOAT_0;
630 }
631 else if (arg == M_PI_2) {
632 y = x;
633 x = RFLOAT_0;
634 }
635 else if (arg == M_PI_2+M_PI) {
636 y = f_negate(x);
637 x = RFLOAT_0;
638 }
639 else if (RB_FLOAT_TYPE_P(x)) {
640 const double abs = RFLOAT_VALUE(x);
641 const double real = abs * cos(arg), imag = abs * sin(arg);
642 x = DBL2NUM(real);
643 y = DBL2NUM(imag);
644 }
645 else {
646 const double ax = sin(arg), ay = cos(arg);
647 y = f_mul(x, DBL2NUM(ax));
648 x = f_mul(x, DBL2NUM(ay));
649 }
650 return nucomp_s_new_internal(klass, x, y);
651 }
652 return nucomp_s_canonicalize_internal(klass,
653 f_mul(x, m_cos(y)),
654 f_mul(x, m_sin(y)));
655}
656
657static VALUE
658f_complex_polar(VALUE klass, VALUE x, VALUE y)
659{
660 x = nucomp_real_check(x);
661 y = nucomp_real_check(y);
662 return f_complex_polar_real(klass, x, y);
663}
664
665#ifdef HAVE___COSPI
666# define cospi(x) __cospi(x)
667#else
668# define cospi(x) cos((x) * M_PI)
669#endif
670#ifdef HAVE___SINPI
671# define sinpi(x) __sinpi(x)
672#else
673# define sinpi(x) sin((x) * M_PI)
674#endif
675/* returns a Complex or Float of ang*PI-rotated abs */
676VALUE
677rb_dbl_complex_new_polar_pi(double abs, double ang)
678{
679 double fi;
680 const double fr = modf(ang, &fi);
681 int pos = fr == +0.5;
682
683 if (pos || fr == -0.5) {
684 if ((modf(fi / 2.0, &fi) != fr) ^ pos) abs = -abs;
685 return rb_complex_new(RFLOAT_0, DBL2NUM(abs));
686 }
687 else if (fr == 0.0) {
688 if (modf(fi / 2.0, &fi) != 0.0) abs = -abs;
689 return DBL2NUM(abs);
690 }
691 else {
692 const double real = abs * cospi(ang), imag = abs * sinpi(ang);
693 return rb_complex_new(DBL2NUM(real), DBL2NUM(imag));
694 }
695}
696
697/*
698 * call-seq:
699 * Complex.polar(abs, arg = 0) -> complex
700 *
701 * Returns a new \Complex object formed from the arguments,
702 * each of which must be an instance of Numeric,
703 * or an instance of one of its subclasses:
704 * \Complex, Float, Integer, Rational.
705 * Argument +arg+ is given in radians;
706 * see {Polar Coordinates}[rdoc-ref:Complex@Polar+Coordinates]:
707 *
708 * Complex.polar(3) # => (3+0i)
709 * Complex.polar(3, 2.0) # => (-1.2484405096414273+2.727892280477045i)
710 * Complex.polar(-3, -2.0) # => (1.2484405096414273+2.727892280477045i)
711 *
712 */
713static VALUE
714nucomp_s_polar(int argc, VALUE *argv, VALUE klass)
715{
716 VALUE abs, arg;
717
718 argc = rb_scan_args(argc, argv, "11", &abs, &arg);
719 abs = nucomp_real_check(abs);
720 if (argc == 2) {
721 arg = nucomp_real_check(arg);
722 }
723 else {
724 arg = ZERO;
725 }
726 return f_complex_polar_real(klass, abs, arg);
727}
728
729/*
730 * call-seq:
731 * real -> numeric
732 *
733 * Returns the real value for +self+:
734 *
735 * Complex.rect(7).real # => 7
736 * Complex.rect(9, -4).real # => 9
737 *
738 * If +self+ was created with
739 * {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates], the returned value
740 * is computed, and may be inexact:
741 *
742 * Complex.polar(1, Math::PI/4).real # => 0.7071067811865476 # Square root of 2.
743 *
744 */
745VALUE
746rb_complex_real(VALUE self)
747{
748 get_dat1(self);
749 return dat->real;
750}
751
752/*
753 * call-seq:
754 * imag -> numeric
755 *
756 * Returns the imaginary value for +self+:
757 *
758 * Complex.rect(7).imag # => 0
759 * Complex.rect(9, -4).imag # => -4
760 *
761 * If +self+ was created with
762 * {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates], the returned value
763 * is computed, and may be inexact:
764 *
765 * Complex.polar(1, Math::PI/4).imag # => 0.7071067811865476 # Square root of 2.
766 *
767 */
768VALUE
769rb_complex_imag(VALUE self)
770{
771 get_dat1(self);
772 return dat->imag;
773}
774
775/*
776 * call-seq:
777 * -self -> complex
778 *
779 * Returns +self+, negated, which is the negation of each of its parts:
780 *
781 * -Complex.rect(1, 2) # => (-1-2i)
782 * -Complex.rect(-1, -2) # => (1+2i)
783 *
784 */
785VALUE
786rb_complex_uminus(VALUE self)
787{
788 get_dat1(self);
789 return f_complex_new2(CLASS_OF(self),
790 f_negate(dat->real), f_negate(dat->imag));
791}
792
793/*
794 * call-seq:
795 * self + other -> numeric
796 *
797 * Returns the sum of +self+ and +other+:
798 *
799 * Complex(1, 2) + 0 # => (1+2i)
800 * Complex(1, 2) + 1 # => (2+2i)
801 * Complex(1, 2) + -1 # => (0+2i)
802 *
803 * Complex(1, 2) + 1.0 # => (2.0+2i)
804 *
805 * Complex(1, 2) + Complex(2, 1) # => (3+3i)
806 * Complex(1, 2) + Complex(2.0, 1.0) # => (3.0+3.0i)
807 *
808 * Complex(1, 2) + Rational(1, 1) # => ((2/1)+2i)
809 * Complex(1, 2) + Rational(1, 2) # => ((3/2)+2i)
810 *
811 * For a computation involving Floats, the result may be inexact (see Float#+):
812 *
813 * Complex(1, 2) + 3.14 # => (4.140000000000001+2i)
814 */
815VALUE
816rb_complex_plus(VALUE self, VALUE other)
817{
818 if (RB_TYPE_P(other, T_COMPLEX)) {
819 VALUE real, imag;
820
821 get_dat2(self, other);
822
823 real = f_add(adat->real, bdat->real);
824 imag = f_add(adat->imag, bdat->imag);
825
826 return f_complex_new2(CLASS_OF(self), real, imag);
827 }
828 if (k_numeric_p(other) && f_real_p(other)) {
829 get_dat1(self);
830
831 return f_complex_new2(CLASS_OF(self),
832 f_add(dat->real, other), dat->imag);
833 }
834 return rb_num_coerce_bin(self, other, '+');
835}
836
837/*
838 * call-seq:
839 * self - other -> complex
840 *
841 * Returns the difference of +self+ and +other+:
842 *
843 * Complex.rect(2, 3) - Complex.rect(2, 3) # => (0+0i)
844 * Complex.rect(900) - Complex.rect(1) # => (899+0i)
845 * Complex.rect(-2, 9) - Complex.rect(-9, 2) # => (7+7i)
846 * Complex.rect(9, 8) - 4 # => (5+8i)
847 * Complex.rect(20, 9) - 9.8 # => (10.2+9i)
848 *
849 */
850VALUE
851rb_complex_minus(VALUE self, VALUE other)
852{
853 if (RB_TYPE_P(other, T_COMPLEX)) {
854 VALUE real, imag;
855
856 get_dat2(self, other);
857
858 real = f_sub(adat->real, bdat->real);
859 imag = f_sub(adat->imag, bdat->imag);
860
861 return f_complex_new2(CLASS_OF(self), real, imag);
862 }
863 if (k_numeric_p(other) && f_real_p(other)) {
864 get_dat1(self);
865
866 return f_complex_new2(CLASS_OF(self),
867 f_sub(dat->real, other), dat->imag);
868 }
869 return rb_num_coerce_bin(self, other, '-');
870}
871
872static VALUE
873safe_mul(VALUE a, VALUE b, bool az, bool bz)
874{
875 double v;
876 if (!az && bz && RB_FLOAT_TYPE_P(a) && (v = RFLOAT_VALUE(a), !isnan(v))) {
877 a = signbit(v) ? DBL2NUM(-1.0) : DBL2NUM(1.0);
878 }
879 if (!bz && az && RB_FLOAT_TYPE_P(b) && (v = RFLOAT_VALUE(b), !isnan(v))) {
880 b = signbit(v) ? DBL2NUM(-1.0) : DBL2NUM(1.0);
881 }
882 return f_mul(a, b);
883}
884
885static void
886comp_mul(VALUE areal, VALUE aimag, VALUE breal, VALUE bimag, VALUE *real, VALUE *imag)
887{
888 bool arzero = f_zero_p(areal);
889 bool aizero = f_zero_p(aimag);
890 bool brzero = f_zero_p(breal);
891 bool bizero = f_zero_p(bimag);
892 *real = f_sub(safe_mul(areal, breal, arzero, brzero),
893 safe_mul(aimag, bimag, aizero, bizero));
894 *imag = f_add(safe_mul(areal, bimag, arzero, bizero),
895 safe_mul(aimag, breal, aizero, brzero));
896}
897
898/*
899 * call-seq:
900 * self * other -> numeric
901 *
902 * Returns the numeric product of +self+ and +other+:
903 *
904 * Complex.rect(9, 8) * 4 # => (36+32i)
905 * Complex.rect(20, 9) * 9.8 # => (196.0+88.2i)
906 * Complex.rect(2, 3) * Complex.rect(2, 3) # => (-5+12i)
907 * Complex.rect(900) * Complex.rect(1) # => (900+0i)
908 * Complex.rect(-2, 9) * Complex.rect(-9, 2) # => (0-85i)
909 * Complex.rect(9, 8) * Rational(2, 3) # => ((6/1)+(16/3)*i)
910 *
911 */
912VALUE
913rb_complex_mul(VALUE self, VALUE other)
914{
915 if (RB_TYPE_P(other, T_COMPLEX)) {
916 VALUE real, imag;
917 get_dat2(self, other);
918
919 comp_mul(adat->real, adat->imag, bdat->real, bdat->imag, &real, &imag);
920
921 return f_complex_new2(CLASS_OF(self), real, imag);
922 }
923 if (k_numeric_p(other) && f_real_p(other)) {
924 get_dat1(self);
925
926 return f_complex_new2(CLASS_OF(self),
927 f_mul(dat->real, other),
928 f_mul(dat->imag, other));
929 }
930 return rb_num_coerce_bin(self, other, '*');
931}
932
933inline static VALUE
934f_divide(VALUE self, VALUE other,
935 VALUE (*func)(VALUE, VALUE), ID id)
936{
937 if (RB_TYPE_P(other, T_COMPLEX)) {
938 VALUE r, n, x, y;
939 int flo;
940 get_dat2(self, other);
941
942 flo = (RB_FLOAT_TYPE_P(adat->real) || RB_FLOAT_TYPE_P(adat->imag) ||
943 RB_FLOAT_TYPE_P(bdat->real) || RB_FLOAT_TYPE_P(bdat->imag));
944
945 if (f_gt_p(f_abs(bdat->real), f_abs(bdat->imag))) {
946 r = (*func)(bdat->imag, bdat->real);
947 n = f_mul(bdat->real, f_add(ONE, f_mul(r, r)));
948 x = (*func)(f_add(adat->real, f_mul(adat->imag, r)), n);
949 y = (*func)(f_sub(adat->imag, f_mul(adat->real, r)), n);
950 }
951 else {
952 r = (*func)(bdat->real, bdat->imag);
953 n = f_mul(bdat->imag, f_add(ONE, f_mul(r, r)));
954 x = (*func)(f_add(f_mul(adat->real, r), adat->imag), n);
955 y = (*func)(f_sub(f_mul(adat->imag, r), adat->real), n);
956 }
957 if (!flo) {
958 x = rb_rational_canonicalize(x);
959 y = rb_rational_canonicalize(y);
960 }
961 return f_complex_new2(CLASS_OF(self), x, y);
962 }
963 if (k_numeric_p(other) && f_real_p(other)) {
964 VALUE x, y;
965 get_dat1(self);
966 x = rb_rational_canonicalize((*func)(dat->real, other));
967 y = rb_rational_canonicalize((*func)(dat->imag, other));
968 return f_complex_new2(CLASS_OF(self), x, y);
969 }
970 return rb_num_coerce_bin(self, other, id);
971}
972
973#define rb_raise_zerodiv() rb_raise(rb_eZeroDivError, "divided by 0")
974
975/*
976 * call-seq:
977 * self / other -> complex
978 *
979 * Returns the quotient of +self+ and +other+:
980 *
981 * Complex.rect(2, 3) / Complex.rect(2, 3) # => (1+0i)
982 * Complex.rect(900) / Complex.rect(1) # => (900+0i)
983 * Complex.rect(-2, 9) / Complex.rect(-9, 2) # => ((36/85)-(77/85)*i)
984 * Complex.rect(9, 8) / 4 # => ((9/4)+2i)
985 * Complex.rect(20, 9) / 9.8 # => (2.0408163265306123+0.9183673469387754i)
986 *
987 */
988VALUE
989rb_complex_div(VALUE self, VALUE other)
990{
991 return f_divide(self, other, f_quo, id_quo);
992}
993
994#define nucomp_quo rb_complex_div
995
996/*
997 * call-seq:
998 * fdiv(numeric) -> new_complex
999 *
1000 * Returns <tt>Complex.rect(self.real/numeric, self.imag/numeric)</tt>:
1001 *
1002 * Complex.rect(11, 22).fdiv(3) # => (3.6666666666666665+7.333333333333333i)
1003 *
1004 */
1005static VALUE
1006nucomp_fdiv(VALUE self, VALUE other)
1007{
1008 return f_divide(self, other, f_fdiv, id_fdiv);
1009}
1010
1011inline static VALUE
1012f_reciprocal(VALUE x)
1013{
1014 return f_quo(ONE, x);
1015}
1016
1017static VALUE
1018zero_for(VALUE x)
1019{
1020 if (RB_FLOAT_TYPE_P(x))
1021 return DBL2NUM(0);
1022 if (RB_TYPE_P(x, T_RATIONAL))
1023 return rb_rational_new(INT2FIX(0), INT2FIX(1));
1024
1025 return INT2FIX(0);
1026}
1027
1028static VALUE
1029complex_pow_for_special_angle(VALUE self, VALUE other)
1030{
1031 if (!rb_integer_type_p(other)) {
1032 return Qundef;
1033 }
1034
1035 get_dat1(self);
1036 VALUE x = Qundef;
1037 int dir;
1038 if (f_zero_p(dat->imag)) {
1039 x = dat->real;
1040 dir = 0;
1041 }
1042 else if (f_zero_p(dat->real)) {
1043 x = dat->imag;
1044 dir = 2;
1045 }
1046 else if (f_eqeq_p(dat->real, dat->imag)) {
1047 x = dat->real;
1048 dir = 1;
1049 }
1050 else if (f_eqeq_p(dat->real, f_negate(dat->imag))) {
1051 x = dat->imag;
1052 dir = 3;
1053 }
1054 else {
1055 dir = 0;
1056 }
1057
1058 if (UNDEF_P(x)) return x;
1059
1060 if (f_negative_p(x)) {
1061 x = f_negate(x);
1062 dir += 4;
1063 }
1064
1065 VALUE zx;
1066 if (dir % 2 == 0) {
1067 zx = rb_num_pow(x, other);
1068 }
1069 else {
1070 zx = rb_num_pow(
1071 rb_funcall(rb_int_mul(TWO, x), '*', 1, x),
1072 rb_int_div(other, TWO)
1073 );
1074 if (rb_int_odd_p(other)) {
1075 zx = rb_funcall(zx, '*', 1, x);
1076 }
1077 }
1078 static const int dirs[][2] = {
1079 {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}
1080 };
1081 int z_dir = FIX2INT(rb_int_modulo(rb_int_mul(INT2FIX(dir), other), INT2FIX(8)));
1082
1083 VALUE zr = Qfalse, zi = Qfalse;
1084 switch (dirs[z_dir][0]) {
1085 case 0: zr = zero_for(zx); break;
1086 case 1: zr = zx; break;
1087 case -1: zr = f_negate(zx); break;
1088 }
1089 switch (dirs[z_dir][1]) {
1090 case 0: zi = zero_for(zx); break;
1091 case 1: zi = zx; break;
1092 case -1: zi = f_negate(zx); break;
1093 }
1094 return nucomp_s_new_internal(CLASS_OF(self), zr, zi);
1095}
1096
1097
1098/*
1099 * call-seq:
1100 * self ** exponent -> complex
1101 *
1102 * Returns +self+ raised to the power +exponent+:
1103 *
1104 * Complex.rect(0, 1) ** 2 # => (-1+0i)
1105 * Complex.rect(-8) ** Rational(1, 3) # => (1.0000000000000002+1.7320508075688772i)
1106 *
1107 */
1108VALUE
1109rb_complex_pow(VALUE self, VALUE other)
1110{
1111 if (k_numeric_p(other) && k_exact_zero_p(other))
1112 return f_complex_new_bang1(CLASS_OF(self), ONE);
1113
1114 if (RB_TYPE_P(other, T_RATIONAL) && RRATIONAL(other)->den == LONG2FIX(1))
1115 other = RRATIONAL(other)->num; /* c14n */
1116
1117 if (RB_TYPE_P(other, T_COMPLEX)) {
1118 get_dat1(other);
1119
1120 if (k_exact_zero_p(dat->imag))
1121 other = dat->real; /* c14n */
1122 }
1123
1124 if (other == ONE) {
1125 get_dat1(self);
1126 return nucomp_s_new_internal(CLASS_OF(self), dat->real, dat->imag);
1127 }
1128
1129 VALUE result = complex_pow_for_special_angle(self, other);
1130 if (!UNDEF_P(result)) return result;
1131
1132 if (RB_TYPE_P(other, T_COMPLEX)) {
1133 VALUE r, theta, nr, ntheta;
1134
1135 get_dat1(other);
1136
1137 r = f_abs(self);
1138 theta = f_arg(self);
1139
1140 nr = m_exp_bang(f_sub(f_mul(dat->real, m_log_bang(r)),
1141 f_mul(dat->imag, theta)));
1142 ntheta = f_add(f_mul(theta, dat->real),
1143 f_mul(dat->imag, m_log_bang(r)));
1144 return f_complex_polar(CLASS_OF(self), nr, ntheta);
1145 }
1146 if (FIXNUM_P(other)) {
1147 long n = FIX2LONG(other);
1148 if (n == 0) {
1149 return nucomp_s_new_internal(CLASS_OF(self), ONE, ZERO);
1150 }
1151 if (n < 0) {
1152 self = f_reciprocal(self);
1153 other = rb_int_uminus(other);
1154 n = -n;
1155 }
1156 {
1157 get_dat1(self);
1158 VALUE xr = dat->real, xi = dat->imag, zr = xr, zi = xi;
1159
1160 if (f_zero_p(xi)) {
1161 zr = rb_num_pow(zr, other);
1162 }
1163 else if (f_zero_p(xr)) {
1164 zi = rb_num_pow(zi, other);
1165 if (n & 2) zi = f_negate(zi);
1166 if (!(n & 1)) {
1167 VALUE tmp = zr;
1168 zr = zi;
1169 zi = tmp;
1170 }
1171 }
1172 else {
1173 while (--n) {
1174 long q, r;
1175
1176 for (; q = n / 2, r = n % 2, r == 0; n = q) {
1177 VALUE tmp = f_sub(f_mul(xr, xr), f_mul(xi, xi));
1178 xi = f_mul(f_mul(TWO, xr), xi);
1179 xr = tmp;
1180 }
1181 comp_mul(zr, zi, xr, xi, &zr, &zi);
1182 }
1183 }
1184 return nucomp_s_new_internal(CLASS_OF(self), zr, zi);
1185 }
1186 }
1187 if (k_numeric_p(other) && f_real_p(other)) {
1188 VALUE r, theta;
1189
1190 if (RB_BIGNUM_TYPE_P(other))
1191 rb_warn("in a**b, b may be too big");
1192
1193 r = rb_num_pow(f_abs(self), other);
1194 theta = f_mul(f_arg(self), other);
1195
1196 return f_complex_polar(CLASS_OF(self), r, theta);
1197 }
1198 return rb_num_coerce_bin(self, other, id_expt);
1199}
1200
1201/*
1202 * call-seq:
1203 * self == other -> true or false
1204 *
1205 * Returns whether both <tt>self.real == other.real</tt>
1206 * and <tt>self.imag == other.imag</tt>:
1207 *
1208 * Complex.rect(2, 3) == Complex.rect(2.0, 3.0) # => true
1209 *
1210 */
1211static VALUE
1212nucomp_eqeq_p(VALUE self, VALUE other)
1213{
1214 if (RB_TYPE_P(other, T_COMPLEX)) {
1215 get_dat2(self, other);
1216
1217 return RBOOL(f_eqeq_p(adat->real, bdat->real) &&
1218 f_eqeq_p(adat->imag, bdat->imag));
1219 }
1220 if (k_numeric_p(other) && f_real_p(other)) {
1221 get_dat1(self);
1222
1223 return RBOOL(f_eqeq_p(dat->real, other) && f_zero_p(dat->imag));
1224 }
1225 return RBOOL(f_eqeq_p(other, self));
1226}
1227
1228static bool
1229nucomp_real_p(VALUE self)
1230{
1231 get_dat1(self);
1232 return f_zero_p(dat->imag);
1233}
1234
1235/*
1236 * call-seq:
1237 * self <=> other -> -1, 0, 1, or nil
1238 *
1239 * Compares +self+ and +other+.
1240 *
1241 * Returns:
1242 *
1243 * - <tt>self.real <=> other.real</tt> if both of the following are true:
1244 *
1245 * - <tt>self.imag == 0</tt>.
1246 * - <tt>other.imag == 0</tt> (always true if +other+ is numeric but not complex).
1247 *
1248 * - +nil+ otherwise.
1249 *
1250 * Examples:
1251 *
1252 * Complex.rect(2) <=> 3 # => -1
1253 * Complex.rect(2) <=> 2 # => 0
1254 * Complex.rect(2) <=> 1 # => 1
1255 * Complex.rect(2, 1) <=> 1 # => nil # self.imag not zero.
1256 * Complex.rect(1) <=> Complex.rect(1, 1) # => nil # object.imag not zero.
1257 * Complex.rect(1) <=> 'Foo' # => nil # object.imag not defined.
1258 *
1259 * \Class \Complex includes module Comparable,
1260 * each of whose methods uses Complex#<=> for comparison.
1261 */
1262static VALUE
1263nucomp_cmp(VALUE self, VALUE other)
1264{
1265 if (!k_numeric_p(other)) {
1266 return rb_num_coerce_cmp(self, other, idCmp);
1267 }
1268 if (!nucomp_real_p(self)) {
1269 return Qnil;
1270 }
1271 if (RB_TYPE_P(other, T_COMPLEX)) {
1272 if (nucomp_real_p(other)) {
1273 get_dat2(self, other);
1274 return rb_funcall(adat->real, idCmp, 1, bdat->real);
1275 }
1276 }
1277 else {
1278 get_dat1(self);
1279 if (f_real_p(other)) {
1280 return rb_funcall(dat->real, idCmp, 1, other);
1281 }
1282 else {
1283 return rb_num_coerce_cmp(dat->real, other, idCmp);
1284 }
1285 }
1286 return Qnil;
1287}
1288
1289/* :nodoc: */
1290static VALUE
1291nucomp_coerce(VALUE self, VALUE other)
1292{
1293 if (RB_TYPE_P(other, T_COMPLEX))
1294 return rb_assoc_new(other, self);
1295 if (k_numeric_p(other) && f_real_p(other))
1296 return rb_assoc_new(f_complex_new_bang1(CLASS_OF(self), other), self);
1297
1298 rb_raise(rb_eTypeError, "%"PRIsVALUE" can't be coerced into %"PRIsVALUE,
1299 rb_obj_class(other), rb_obj_class(self));
1300 return Qnil;
1301}
1302
1303/*
1304 * call-seq:
1305 * abs -> float
1306 *
1307 * Returns the absolute value (magnitude) for +self+;
1308 * see {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates]:
1309 *
1310 * Complex.polar(-1, 0).abs # => 1.0
1311 *
1312 * If +self+ was created with
1313 * {rectangular coordinates}[rdoc-ref:Complex@Rectangular+Coordinates], the returned value
1314 * is computed, and may be inexact:
1315 *
1316 * Complex.rectangular(1, 1).abs # => 1.4142135623730951 # The square root of 2.
1317 *
1318 */
1319VALUE
1320rb_complex_abs(VALUE self)
1321{
1322 get_dat1(self);
1323
1324 if (f_zero_p(dat->real)) {
1325 VALUE a = f_abs(dat->imag);
1326 if (RB_FLOAT_TYPE_P(dat->real) && !RB_FLOAT_TYPE_P(dat->imag))
1327 a = f_to_f(a);
1328 return a;
1329 }
1330 if (f_zero_p(dat->imag)) {
1331 VALUE a = f_abs(dat->real);
1332 if (!RB_FLOAT_TYPE_P(dat->real) && RB_FLOAT_TYPE_P(dat->imag))
1333 a = f_to_f(a);
1334 return a;
1335 }
1336 return rb_math_hypot(dat->real, dat->imag);
1337}
1338
1339/*
1340 * call-seq:
1341 * abs2 -> float
1342 *
1343 * Returns square of the absolute value (magnitude) for +self+;
1344 * see {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates]:
1345 *
1346 * Complex.polar(2, 2).abs2 # => 4.0
1347 *
1348 * If +self+ was created with
1349 * {rectangular coordinates}[rdoc-ref:Complex@Rectangular+Coordinates], the returned value
1350 * is computed, and may be inexact:
1351 *
1352 * Complex.rectangular(1.0/3, 1.0/3).abs2 # => 0.2222222222222222
1353 *
1354 */
1355static VALUE
1356nucomp_abs2(VALUE self)
1357{
1358 get_dat1(self);
1359 return f_add(f_mul(dat->real, dat->real),
1360 f_mul(dat->imag, dat->imag));
1361}
1362
1363/*
1364 * call-seq:
1365 * arg -> float
1366 *
1367 * Returns the argument (angle) for +self+ in radians;
1368 * see {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates]:
1369 *
1370 * Complex.polar(3, Math::PI/2).arg # => 1.57079632679489660
1371 *
1372 * If +self+ was created with
1373 * {rectangular coordinates}[rdoc-ref:Complex@Rectangular+Coordinates], the returned value
1374 * is computed, and may be inexact:
1375 *
1376 * Complex.polar(1, 1.0/3).arg # => 0.33333333333333326
1377 *
1378 */
1379VALUE
1380rb_complex_arg(VALUE self)
1381{
1382 get_dat1(self);
1383 return rb_math_atan2(dat->imag, dat->real);
1384}
1385
1386/*
1387 * call-seq:
1388 * rect -> array
1389 *
1390 * Returns the array <tt>[self.real, self.imag]</tt>:
1391 *
1392 * Complex.rect(1, 2).rect # => [1, 2]
1393 *
1394 * See {Rectangular Coordinates}[rdoc-ref:Complex@Rectangular+Coordinates].
1395 *
1396 * If +self+ was created with
1397 * {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates], the returned value
1398 * is computed, and may be inexact:
1399 *
1400 * Complex.polar(1.0, 1.0).rect # => [0.5403023058681398, 0.8414709848078965]
1401 *
1402 *
1403 * Complex#rectangular is an alias for Complex#rect.
1404 */
1405static VALUE
1406nucomp_rect(VALUE self)
1407{
1408 get_dat1(self);
1409 return rb_assoc_new(dat->real, dat->imag);
1410}
1411
1412/*
1413 * call-seq:
1414 * polar -> array
1415 *
1416 * Returns the array <tt>[self.abs, self.arg]</tt>:
1417 *
1418 * Complex.polar(1, 2).polar # => [1.0, 2.0]
1419 *
1420 * See {Polar Coordinates}[rdoc-ref:Complex@Polar+Coordinates].
1421 *
1422 * If +self+ was created with
1423 * {rectangular coordinates}[rdoc-ref:Complex@Rectangular+Coordinates], the returned value
1424 * is computed, and may be inexact:
1425 *
1426 * Complex.rect(1, 1).polar # => [1.4142135623730951, 0.7853981633974483]
1427 *
1428 */
1429static VALUE
1430nucomp_polar(VALUE self)
1431{
1432 return rb_assoc_new(f_abs(self), f_arg(self));
1433}
1434
1435/*
1436 * call-seq:
1437 * conj -> complex
1438 *
1439 * Returns the conjugate of +self+, <tt>Complex.rect(self.imag, self.real)</tt>:
1440 *
1441 * Complex.rect(1, 2).conj # => (1-2i)
1442 *
1443 */
1444VALUE
1445rb_complex_conjugate(VALUE self)
1446{
1447 get_dat1(self);
1448 return f_complex_new2(CLASS_OF(self), dat->real, f_negate(dat->imag));
1449}
1450
1451/*
1452 * call-seq:
1453 * real? -> false
1454 *
1455 * Returns +false+; for compatibility with Numeric#real?.
1456 */
1457static VALUE
1458nucomp_real_p_m(VALUE self)
1459{
1460 return Qfalse;
1461}
1462
1463/*
1464 * call-seq:
1465 * denominator -> integer
1466 *
1467 * Returns the denominator of +self+, which is
1468 * the {least common multiple}[https://en.wikipedia.org/wiki/Least_common_multiple]
1469 * of <tt>self.real.denominator</tt> and <tt>self.imag.denominator</tt>:
1470 *
1471 * Complex.rect(Rational(1, 2), Rational(2, 3)).denominator # => 6
1472 *
1473 * Note that <tt>n.denominator</tt> of a non-rational numeric is +1+.
1474 *
1475 * Related: Complex#numerator.
1476 */
1477static VALUE
1478nucomp_denominator(VALUE self)
1479{
1480 get_dat1(self);
1481 return rb_lcm(f_denominator(dat->real), f_denominator(dat->imag));
1482}
1483
1484/*
1485 * call-seq:
1486 * numerator -> new_complex
1487 *
1488 * Returns the \Complex object created from the numerators
1489 * of the real and imaginary parts of +self+,
1490 * after converting each part to the
1491 * {lowest common denominator}[https://en.wikipedia.org/wiki/Lowest_common_denominator]
1492 * of the two:
1493 *
1494 * c = Complex.rect(Rational(2, 3), Rational(3, 4)) # => ((2/3)+(3/4)*i)
1495 * c.numerator # => (8+9i)
1496 *
1497 * In this example, the lowest common denominator of the two parts is 12;
1498 * the two converted parts may be thought of as \Rational(8, 12) and \Rational(9, 12),
1499 * whose numerators, respectively, are 8 and 9;
1500 * so the returned value of <tt>c.numerator</tt> is <tt>Complex.rect(8, 9)</tt>.
1501 *
1502 * Related: Complex#denominator.
1503 */
1504static VALUE
1505nucomp_numerator(VALUE self)
1506{
1507 VALUE cd;
1508
1509 get_dat1(self);
1510
1511 cd = nucomp_denominator(self);
1512 return f_complex_new2(CLASS_OF(self),
1513 f_mul(f_numerator(dat->real),
1514 f_div(cd, f_denominator(dat->real))),
1515 f_mul(f_numerator(dat->imag),
1516 f_div(cd, f_denominator(dat->imag))));
1517}
1518
1519/* :nodoc: */
1520st_index_t
1521rb_complex_hash(VALUE self)
1522{
1523 st_index_t v, h[2];
1524 VALUE n;
1525
1526 get_dat1(self);
1527 n = rb_hash(dat->real);
1528 h[0] = NUM2LONG(n);
1529 n = rb_hash(dat->imag);
1530 h[1] = NUM2LONG(n);
1531 v = rb_memhash(h, sizeof(h));
1532 return v;
1533}
1534
1535/*
1536 * :call-seq:
1537 * hash -> integer
1538 *
1539 * Returns the integer hash value for +self+.
1540 *
1541 * Two \Complex objects created from the same values will have the same hash value
1542 * (and will compare using #eql?):
1543 *
1544 * Complex.rect(1, 2).hash == Complex.rect(1, 2).hash # => true
1545 *
1546 */
1547static VALUE
1548nucomp_hash(VALUE self)
1549{
1550 return ST2FIX(rb_complex_hash(self));
1551}
1552
1553/* :nodoc: */
1554static VALUE
1555nucomp_eql_p(VALUE self, VALUE other)
1556{
1557 if (RB_TYPE_P(other, T_COMPLEX)) {
1558 get_dat2(self, other);
1559
1560 return RBOOL((CLASS_OF(adat->real) == CLASS_OF(bdat->real)) &&
1561 (CLASS_OF(adat->imag) == CLASS_OF(bdat->imag)) &&
1562 f_eqeq_p(self, other));
1563
1564 }
1565 return Qfalse;
1566}
1567
1568inline static int
1569f_signbit(VALUE x)
1570{
1571 if (RB_FLOAT_TYPE_P(x)) {
1572 double f = RFLOAT_VALUE(x);
1573 return !isnan(f) && signbit(f);
1574 }
1575 return f_negative_p(x);
1576}
1577
1578inline static int
1579f_tpositive_p(VALUE x)
1580{
1581 return !f_signbit(x);
1582}
1583
1584static VALUE
1585f_format(VALUE self, VALUE s, VALUE (*func)(VALUE))
1586{
1587 int impos;
1588
1589 get_dat1(self);
1590
1591 impos = f_tpositive_p(dat->imag);
1592
1593 rb_str_concat(s, (*func)(dat->real));
1594 rb_str_cat2(s, !impos ? "-" : "+");
1595
1596 rb_str_concat(s, (*func)(f_abs(dat->imag)));
1597 if (!rb_isdigit(RSTRING_PTR(s)[RSTRING_LEN(s) - 1]))
1598 rb_str_cat2(s, "*");
1599 rb_str_cat2(s, "i");
1600
1601 return s;
1602}
1603
1604/*
1605 * call-seq:
1606 * to_s -> string
1607 *
1608 * Returns a string representation of +self+:
1609 *
1610 * Complex.rect(2).to_s # => "2+0i"
1611 * Complex.rect(-8, 6).to_s # => "-8+6i"
1612 * Complex.rect(0, Rational(1, 2)).to_s # => "0+1/2i"
1613 * Complex.rect(0, Float::INFINITY).to_s # => "0+Infinity*i"
1614 * Complex.rect(Float::NAN, Float::NAN).to_s # => "NaN+NaN*i"
1615 *
1616 */
1617static VALUE
1618nucomp_to_s(VALUE self)
1619{
1620 return f_format(self, rb_usascii_str_new2(""), rb_String);
1621}
1622
1623/*
1624 * call-seq:
1625 * inspect -> string
1626 *
1627 * Returns a string representation of +self+:
1628 *
1629 * Complex.rect(2).inspect # => "(2+0i)"
1630 * Complex.rect(-8, 6).inspect # => "(-8+6i)"
1631 * Complex.rect(0, Rational(1, 2)).inspect # => "(0+(1/2)*i)"
1632 * Complex.rect(0, Float::INFINITY).inspect # => "(0+Infinity*i)"
1633 * Complex.rect(Float::NAN, Float::NAN).inspect # => "(NaN+NaN*i)"
1634 *
1635 */
1636static VALUE
1637nucomp_inspect(VALUE self)
1638{
1639 VALUE s;
1640
1641 s = rb_usascii_str_new2("(");
1642 f_format(self, s, rb_inspect);
1643 rb_str_cat2(s, ")");
1644
1645 return s;
1646}
1647
1648#define FINITE_TYPE_P(v) (RB_INTEGER_TYPE_P(v) || RB_TYPE_P(v, T_RATIONAL))
1649
1650/*
1651 * call-seq:
1652 * finite? -> true or false
1653 *
1654 * Returns +true+ if both <tt>self.real.finite?</tt> and <tt>self.imag.finite?</tt>
1655 * are true, +false+ otherwise:
1656 *
1657 * Complex.rect(1, 1).finite? # => true
1658 * Complex.rect(Float::INFINITY, 0).finite? # => false
1659 *
1660 * Related: Numeric#finite?, Float#finite?.
1661 */
1662static VALUE
1663rb_complex_finite_p(VALUE self)
1664{
1665 get_dat1(self);
1666
1667 return RBOOL(f_finite_p(dat->real) && f_finite_p(dat->imag));
1668}
1669
1670/*
1671 * call-seq:
1672 * infinite? -> 1 or nil
1673 *
1674 * Returns +1+ if either <tt>self.real.infinite?</tt> or <tt>self.imag.infinite?</tt>
1675 * is true, +nil+ otherwise:
1676 *
1677 * Complex.rect(Float::INFINITY, 0).infinite? # => 1
1678 * Complex.rect(1, 1).infinite? # => nil
1679 *
1680 * Related: Numeric#infinite?, Float#infinite?.
1681 */
1682static VALUE
1683rb_complex_infinite_p(VALUE self)
1684{
1685 get_dat1(self);
1686
1687 if (!f_infinite_p(dat->real) && !f_infinite_p(dat->imag)) {
1688 return Qnil;
1689 }
1690 return ONE;
1691}
1692
1693/* :nodoc: */
1694static VALUE
1695nucomp_dumper(VALUE self)
1696{
1697 return self;
1698}
1699
1700/* :nodoc: */
1701static VALUE
1702nucomp_loader(VALUE self, VALUE a)
1703{
1704 get_dat1(self);
1705
1706 RCOMPLEX_SET_REAL(dat, rb_ivar_get(a, id_i_real));
1707 RCOMPLEX_SET_IMAG(dat, rb_ivar_get(a, id_i_imag));
1708 OBJ_FREEZE(self);
1709
1710 return self;
1711}
1712
1713/* :nodoc: */
1714static VALUE
1715nucomp_marshal_dump(VALUE self)
1716{
1717 VALUE a;
1718 get_dat1(self);
1719
1720 a = rb_assoc_new(dat->real, dat->imag);
1721 rb_copy_generic_ivar(a, self);
1722 return a;
1723}
1724
1725/* :nodoc: */
1726static VALUE
1727nucomp_marshal_load(VALUE self, VALUE a)
1728{
1729 Check_Type(a, T_ARRAY);
1730 if (RARRAY_LEN(a) != 2)
1731 rb_raise(rb_eArgError, "marshaled complex must have an array whose length is 2 but %ld", RARRAY_LEN(a));
1732 rb_ivar_set(self, id_i_real, RARRAY_AREF(a, 0));
1733 rb_ivar_set(self, id_i_imag, RARRAY_AREF(a, 1));
1734 return self;
1735}
1736
1737VALUE
1738rb_complex_raw(VALUE x, VALUE y)
1739{
1740 return nucomp_s_new_internal(rb_cComplex, x, y);
1741}
1742
1743VALUE
1744rb_complex_new(VALUE x, VALUE y)
1745{
1746 return nucomp_s_canonicalize_internal(rb_cComplex, x, y);
1747}
1748
1749VALUE
1750rb_complex_new_polar(VALUE x, VALUE y)
1751{
1752 return f_complex_polar(rb_cComplex, x, y);
1753}
1754
1755VALUE
1756rb_Complex(VALUE x, VALUE y)
1757{
1758 VALUE a[2];
1759 a[0] = x;
1760 a[1] = y;
1761 return nucomp_s_convert(2, a, rb_cComplex);
1762}
1763
1764VALUE
1765rb_dbl_complex_new(double real, double imag)
1766{
1767 return rb_complex_raw(DBL2NUM(real), DBL2NUM(imag));
1768}
1769
1770/*
1771 * call-seq:
1772 * to_i -> integer
1773 *
1774 * Returns the value of <tt>self.real</tt> as an Integer, if possible:
1775 *
1776 * Complex.rect(1, 0).to_i # => 1
1777 * Complex.rect(1, Rational(0, 1)).to_i # => 1
1778 *
1779 * Raises RangeError if <tt>self.imag</tt> is not exactly zero
1780 * (either <tt>Integer(0)</tt> or <tt>Rational(0, n)</tt>).
1781 */
1782static VALUE
1783nucomp_to_i(VALUE self)
1784{
1785 get_dat1(self);
1786
1787 if (!k_exact_zero_p(dat->imag)) {
1788 rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Integer",
1789 self);
1790 }
1791 return f_to_i(dat->real);
1792}
1793
1794/*
1795 * call-seq:
1796 * to_f -> float
1797 *
1798 * Returns the value of <tt>self.real</tt> as a Float, if possible:
1799 *
1800 * Complex.rect(1, 0).to_f # => 1.0
1801 * Complex.rect(1, Rational(0, 1)).to_f # => 1.0
1802 *
1803 * Raises RangeError if <tt>self.imag</tt> is not exactly zero
1804 * (either <tt>Integer(0)</tt> or <tt>Rational(0, n)</tt>).
1805 */
1806static VALUE
1807nucomp_to_f(VALUE self)
1808{
1809 get_dat1(self);
1810
1811 if (!k_exact_zero_p(dat->imag)) {
1812 rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Float",
1813 self);
1814 }
1815 return f_to_f(dat->real);
1816}
1817
1818/*
1819 * call-seq:
1820 * to_r -> rational
1821 *
1822 * Returns the value of <tt>self.real</tt> as a Rational, if possible:
1823 *
1824 * Complex.rect(1, 0).to_r # => (1/1)
1825 * Complex.rect(1, Rational(0, 1)).to_r # => (1/1)
1826 * Complex.rect(1, 0.0).to_r # => (1/1)
1827 *
1828 * Raises RangeError if <tt>self.imag</tt> is not exactly zero
1829 * (either <tt>Integer(0)</tt> or <tt>Rational(0, n)</tt>)
1830 * and <tt>self.imag.to_r</tt> is not exactly zero.
1831 *
1832 * Related: Complex#rationalize.
1833 */
1834static VALUE
1835nucomp_to_r(VALUE self)
1836{
1837 get_dat1(self);
1838
1839 if (RB_FLOAT_TYPE_P(dat->imag) && FLOAT_ZERO_P(dat->imag)) {
1840 /* Do nothing here */
1841 }
1842 else if (!k_exact_zero_p(dat->imag)) {
1843 VALUE imag = rb_check_convert_type_with_id(dat->imag, T_RATIONAL, "Rational", idTo_r);
1844 if (NIL_P(imag) || !k_exact_zero_p(imag)) {
1845 rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Rational",
1846 self);
1847 }
1848 }
1849 return rb_funcallv(dat->real, id_to_r, 0, 0);
1850}
1851
1852/*
1853 * call-seq:
1854 * rationalize(epsilon = nil) -> rational
1855 *
1856 * Returns a Rational object whose value is exactly or approximately
1857 * equivalent to that of <tt>self.real</tt>.
1858 *
1859 * With no argument +epsilon+ given, returns a \Rational object
1860 * whose value is exactly equal to that of <tt>self.real.rationalize</tt>:
1861 *
1862 * Complex.rect(1, 0).rationalize # => (1/1)
1863 * Complex.rect(1, Rational(0, 1)).rationalize # => (1/1)
1864 * Complex.rect(3.14159, 0).rationalize # => (314159/100000)
1865 *
1866 * With argument +epsilon+ given, returns a \Rational object
1867 * whose value is exactly or approximately equal to that of <tt>self.real</tt>
1868 * to the given precision:
1869 *
1870 * Complex.rect(3.14159, 0).rationalize(0.1) # => (16/5)
1871 * Complex.rect(3.14159, 0).rationalize(0.01) # => (22/7)
1872 * Complex.rect(3.14159, 0).rationalize(0.001) # => (201/64)
1873 * Complex.rect(3.14159, 0).rationalize(0.0001) # => (333/106)
1874 * Complex.rect(3.14159, 0).rationalize(0.00001) # => (355/113)
1875 * Complex.rect(3.14159, 0).rationalize(0.000001) # => (7433/2366)
1876 * Complex.rect(3.14159, 0).rationalize(0.0000001) # => (9208/2931)
1877 * Complex.rect(3.14159, 0).rationalize(0.00000001) # => (47460/15107)
1878 * Complex.rect(3.14159, 0).rationalize(0.000000001) # => (76149/24239)
1879 * Complex.rect(3.14159, 0).rationalize(0.0000000001) # => (314159/100000)
1880 * Complex.rect(3.14159, 0).rationalize(0.0) # => (3537115888337719/1125899906842624)
1881 *
1882 * Related: Complex#to_r.
1883 */
1884static VALUE
1885nucomp_rationalize(int argc, VALUE *argv, VALUE self)
1886{
1887 get_dat1(self);
1888
1889 rb_check_arity(argc, 0, 1);
1890
1891 if (!k_exact_zero_p(dat->imag)) {
1892 rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Rational",
1893 self);
1894 }
1895 return rb_funcallv(dat->real, id_rationalize, argc, argv);
1896}
1897
1898/*
1899 * call-seq:
1900 * to_c -> self
1901 *
1902 * Returns +self+.
1903 */
1904static VALUE
1905nucomp_to_c(VALUE self)
1906{
1907 return self;
1908}
1909
1910/*
1911 * call-seq:
1912 * to_c -> complex
1913 *
1914 * Returns +self+ as a Complex object.
1915 */
1916static VALUE
1917numeric_to_c(VALUE self)
1918{
1919 return rb_complex_new1(self);
1920}
1921
1922inline static int
1923issign(int c)
1924{
1925 return (c == '-' || c == '+');
1926}
1927
1928static int
1929read_sign(const char **s,
1930 char **b)
1931{
1932 int sign = '?';
1933
1934 if (issign(**s)) {
1935 sign = **b = **s;
1936 (*s)++;
1937 (*b)++;
1938 }
1939 return sign;
1940}
1941
1942inline static int
1943isdecimal(int c)
1944{
1945 return isdigit((unsigned char)c);
1946}
1947
1948static int
1949read_digits(const char **s, int strict,
1950 char **b)
1951{
1952 int us = 1;
1953
1954 if (!isdecimal(**s))
1955 return 0;
1956
1957 while (isdecimal(**s) || **s == '_') {
1958 if (**s == '_') {
1959 if (us) {
1960 if (strict) return 0;
1961 break;
1962 }
1963 us = 1;
1964 }
1965 else {
1966 **b = **s;
1967 (*b)++;
1968 us = 0;
1969 }
1970 (*s)++;
1971 }
1972 if (us)
1973 do {
1974 (*s)--;
1975 } while (**s == '_');
1976 return 1;
1977}
1978
1979inline static int
1980islettere(int c)
1981{
1982 return (c == 'e' || c == 'E');
1983}
1984
1985static int
1986read_num(const char **s, int strict,
1987 char **b)
1988{
1989 if (**s != '.') {
1990 if (!read_digits(s, strict, b))
1991 return 0;
1992 }
1993
1994 if (**s == '.') {
1995 **b = **s;
1996 (*s)++;
1997 (*b)++;
1998 if (!read_digits(s, strict, b)) {
1999 (*b)--;
2000 return 0;
2001 }
2002 }
2003
2004 if (islettere(**s)) {
2005 **b = **s;
2006 (*s)++;
2007 (*b)++;
2008 read_sign(s, b);
2009 if (!read_digits(s, strict, b)) {
2010 (*b)--;
2011 return 0;
2012 }
2013 }
2014 return 1;
2015}
2016
2017inline static int
2018read_den(const char **s, int strict,
2019 char **b)
2020{
2021 if (!read_digits(s, strict, b))
2022 return 0;
2023 return 1;
2024}
2025
2026static int
2027read_rat_nos(const char **s, int strict,
2028 char **b)
2029{
2030 if (!read_num(s, strict, b))
2031 return 0;
2032 if (**s == '/') {
2033 **b = **s;
2034 (*s)++;
2035 (*b)++;
2036 if (!read_den(s, strict, b)) {
2037 (*b)--;
2038 return 0;
2039 }
2040 }
2041 return 1;
2042}
2043
2044static int
2045read_rat(const char **s, int strict,
2046 char **b)
2047{
2048 read_sign(s, b);
2049 if (!read_rat_nos(s, strict, b))
2050 return 0;
2051 return 1;
2052}
2053
2054inline static int
2055isimagunit(int c)
2056{
2057 return (c == 'i' || c == 'I' ||
2058 c == 'j' || c == 'J');
2059}
2060
2061static VALUE
2062str2num(char *s)
2063{
2064 if (strchr(s, '/'))
2065 return rb_cstr_to_rat(s, 0);
2066 if (strpbrk(s, ".eE"))
2067 return DBL2NUM(rb_cstr_to_dbl(s, 0));
2068 return rb_cstr_to_inum(s, 10, 0);
2069}
2070
2071static int
2072read_comp(const char **s, int strict,
2073 VALUE *ret, char **b)
2074{
2075 char *bb;
2076 int sign;
2077 VALUE num, num2;
2078
2079 bb = *b;
2080
2081 sign = read_sign(s, b);
2082
2083 if (isimagunit(**s)) {
2084 (*s)++;
2085 num = INT2FIX((sign == '-') ? -1 : + 1);
2086 *ret = rb_complex_new2(ZERO, num);
2087 return 1; /* e.g. "i" */
2088 }
2089
2090 if (!read_rat_nos(s, strict, b)) {
2091 **b = '\0';
2092 num = str2num(bb);
2093 *ret = rb_complex_new2(num, ZERO);
2094 return 0; /* e.g. "-" */
2095 }
2096 **b = '\0';
2097 num = str2num(bb);
2098
2099 if (isimagunit(**s)) {
2100 (*s)++;
2101 *ret = rb_complex_new2(ZERO, num);
2102 return 1; /* e.g. "3i" */
2103 }
2104
2105 if (**s == '@') {
2106 int st;
2107
2108 (*s)++;
2109 bb = *b;
2110 st = read_rat(s, strict, b);
2111 **b = '\0';
2112 if (strlen(bb) < 1 ||
2113 !isdecimal(*(bb + strlen(bb) - 1))) {
2114 *ret = rb_complex_new2(num, ZERO);
2115 return 0; /* e.g. "1@-" */
2116 }
2117 num2 = str2num(bb);
2118 *ret = rb_complex_new_polar(num, num2);
2119 if (!st)
2120 return 0; /* e.g. "1@2." */
2121 else
2122 return 1; /* e.g. "1@2" */
2123 }
2124
2125 if (issign(**s)) {
2126 bb = *b;
2127 sign = read_sign(s, b);
2128 if (isimagunit(**s))
2129 num2 = INT2FIX((sign == '-') ? -1 : + 1);
2130 else {
2131 if (!read_rat_nos(s, strict, b)) {
2132 *ret = rb_complex_new2(num, ZERO);
2133 return 0; /* e.g. "1+xi" */
2134 }
2135 **b = '\0';
2136 num2 = str2num(bb);
2137 }
2138 if (!isimagunit(**s)) {
2139 *ret = rb_complex_new2(num, ZERO);
2140 return 0; /* e.g. "1+3x" */
2141 }
2142 (*s)++;
2143 *ret = rb_complex_new2(num, num2);
2144 return 1; /* e.g. "1+2i" */
2145 }
2146 /* !(@, - or +) */
2147 {
2148 *ret = rb_complex_new2(num, ZERO);
2149 return 1; /* e.g. "3" */
2150 }
2151}
2152
2153inline static void
2154skip_ws(const char **s)
2155{
2156 while (isspace((unsigned char)**s))
2157 (*s)++;
2158}
2159
2160static int
2161parse_comp(const char *s, int strict, VALUE *num)
2162{
2163 char *buf, *b;
2164 VALUE tmp;
2165 int ret = 1;
2166
2167 buf = ALLOCV_N(char, tmp, strlen(s) + 1);
2168 b = buf;
2169
2170 skip_ws(&s);
2171 if (!read_comp(&s, strict, num, &b)) {
2172 ret = 0;
2173 }
2174 else {
2175 skip_ws(&s);
2176
2177 if (strict)
2178 if (*s != '\0')
2179 ret = 0;
2180 }
2181 ALLOCV_END(tmp);
2182
2183 return ret;
2184}
2185
2186static VALUE
2187string_to_c_strict(VALUE self, int raise)
2188{
2189 char *s;
2190 VALUE num;
2191
2192 rb_must_asciicompat(self);
2193
2194 if (raise) {
2195 s = StringValueCStr(self);
2196 }
2197 else if (!(s = rb_str_to_cstr(self))) {
2198 return Qnil;
2199 }
2200
2201 if (!parse_comp(s, TRUE, &num)) {
2202 if (!raise) return Qnil;
2203 rb_raise(rb_eArgError, "invalid value for convert(): %+"PRIsVALUE,
2204 self);
2205 }
2206
2207 return num;
2208}
2209
2210/*
2211 * call-seq:
2212 * to_c -> complex
2213 *
2214 * Returns a Complex object:
2215 * parses the leading substring of +self+
2216 * to extract two numeric values that become the coordinates of the complex object.
2217 *
2218 * The substring is interpreted as containing
2219 * either rectangular coordinates (real and imaginary parts)
2220 * or polar coordinates (magnitude and angle parts),
2221 * depending on an included or implied "separator" character:
2222 *
2223 * - <tt>'+'</tt>, <tt>'-'</tt>, or no separator: rectangular coordinates.
2224 * - <tt>'@'</tt>: polar coordinates.
2225 *
2226 * <b>In Brief</b>
2227 *
2228 * In these examples, we use method Complex#rect to display rectangular coordinates,
2229 * and method Complex#polar to display polar coordinates.
2230 *
2231 * # Rectangular coordinates.
2232 *
2233 * # Real-only: no separator; imaginary part is zero.
2234 * '9'.to_c.rect # => [9, 0] # Integer.
2235 * '-9'.to_c.rect # => [-9, 0] # Integer (negative).
2236 * '2.5'.to_c.rect # => [2.5, 0] # Float.
2237 * '1.23e-14'.to_c.rect # => [1.23e-14, 0] # Float with exponent.
2238 * '2.5/1'.to_c.rect # => [(5/2), 0] # Rational.
2239 *
2240 * # Some things are ignored.
2241 * 'foo1'.to_c.rect # => [0, 0] # Unparsed entire substring.
2242 * '1foo'.to_c.rect # => [1, 0] # Unparsed trailing substring.
2243 * ' 1 '.to_c.rect # => [1, 0] # Leading and trailing whitespace.
2244 * *
2245 * # Imaginary only: trailing 'i' required; real part is zero.
2246 * '9i'.to_c.rect # => [0, 9]
2247 * '-9i'.to_c.rect # => [0, -9]
2248 * '2.5i'.to_c.rect # => [0, 2.5]
2249 * '1.23e-14i'.to_c.rect # => [0, 1.23e-14]
2250 * '2.5/1i'.to_c.rect # => [0, (5/2)]
2251 *
2252 * # Real and imaginary; '+' or '-' separator; trailing 'i' required.
2253 * '2+3i'.to_c.rect # => [2, 3]
2254 * '-2-3i'.to_c.rect # => [-2, -3]
2255 * '2.5+3i'.to_c.rect # => [2.5, 3]
2256 * '2.5+3/2i'.to_c.rect # => [2.5, (3/2)]
2257 *
2258 * # Polar coordinates; '@' separator; magnitude required.
2259 * '1.0@0'.to_c.polar # => [1.0, 0.0]
2260 * '1.0@'.to_c.polar # => [1.0, 0.0]
2261 * "1.0@#{Math::PI}".to_c.polar # => [1.0, 3.141592653589793]
2262 * "1.0@#{Math::PI/2}".to_c.polar # => [1.0, 1.5707963267948966]
2263 *
2264 * <b>Parsed Values</b>
2265 *
2266 * The parsing may be thought of as searching for numeric literals
2267 * embedded in the substring.
2268 *
2269 * This section shows how the method parses numeric values from leading substrings.
2270 * The examples show real-only or imaginary-only parsing;
2271 * the parsing is the same for each part.
2272 *
2273 * '1foo'.to_c # => (1+0i) # Ignores trailing unparsed characters.
2274 * ' 1 '.to_c # => (1+0i) # Ignores leading and trailing whitespace.
2275 * 'x1'.to_c # => (0+0i) # Finds no leading numeric.
2276 *
2277 * # Integer literal embedded in the substring.
2278 * '1'.to_c # => (1+0i)
2279 * '-1'.to_c # => (-1+0i)
2280 * '1i'.to_c # => (0+1i)
2281 *
2282 * # Integer literals that don't work.
2283 * '0b100'.to_c # => (0+0i) # Not parsed as binary.
2284 * '0o100'.to_c # => (0+0i) # Not parsed as octal.
2285 * '0d100'.to_c # => (0+0i) # Not parsed as decimal.
2286 * '0x100'.to_c # => (0+0i) # Not parsed as hexadecimal.
2287 * '010'.to_c # => (10+0i) # Not parsed as octal.
2288 *
2289 * # Float literals:
2290 * '3.14'.to_c # => (3.14+0i)
2291 * '3.14i'.to_c # => (0+3.14i)
2292 * '1.23e4'.to_c # => (12300.0+0i)
2293 * '1.23e+4'.to_c # => (12300.0+0i)
2294 * '1.23e-4'.to_c # => (0.000123+0i)
2295 *
2296 * # Rational literals:
2297 * '1/2'.to_c # => ((1/2)+0i)
2298 * '-1/2'.to_c # => ((-1/2)+0i)
2299 * '1/2r'.to_c # => ((1/2)+0i)
2300 * '-1/2r'.to_c # => ((-1/2)+0i)
2301 *
2302 * <b>Rectangular Coordinates</b>
2303 *
2304 * With separator <tt>'+'</tt> or <tt>'-'</tt>,
2305 * or with no separator,
2306 * interprets the values as rectangular coordinates: real and imaginary.
2307 *
2308 * With no separator, assigns a single value to either the real or the imaginary part:
2309 *
2310 * ''.to_c # => (0+0i) # Defaults to zero.
2311 * '1'.to_c # => (1+0i) # Real (no trailing 'i').
2312 * '1i'.to_c # => (0+1i) # Imaginary (trailing 'i').
2313 * 'i'.to_c # => (0+1i) # Special case (imaginary 1).
2314 *
2315 * With separator <tt>'+'</tt>, both parts positive (or zero):
2316 *
2317 * # Without trailing 'i'.
2318 * '+'.to_c # => (0+0i) # No values: defaults to zero.
2319 * '+1'.to_c # => (1+0i) # Value after '+': real only.
2320 * '1+'.to_c # => (1+0i) # Value before '+': real only.
2321 * '2+1'.to_c # => (2+0i) # Values before and after '+': real and imaginary.
2322 * # With trailing 'i'.
2323 * '+1i'.to_c # => (0+1i) # Value after '+': imaginary only.
2324 * '2+i'.to_c # => (2+1i) # Value before '+': real and imaginary 1.
2325 * '2+1i'.to_c # => (2+1i) # Values before and after '+': real and imaginary.
2326 *
2327 * With separator <tt>'-'</tt>, negative imaginary part:
2328 *
2329 * # Without trailing 'i'.
2330 * '-'.to_c # => (0+0i) # No values: defaults to zero.
2331 * '-1'.to_c # => (-1+0i) # Value after '-': negative real, zero imaginary.
2332 * '1-'.to_c # => (1+0i) # Value before '-': positive real, zero imaginary.
2333 * '2-1'.to_c # => (2+0i) # Values before and after '-': positive real, zero imaginary.
2334 * # With trailing 'i'.
2335 * '-1i'.to_c # => (0-1i) # Value after '-': negative real, zero imaginary.
2336 * '2-i'.to_c # => (2-1i) # Value before '-': positive real, negative imaginary.
2337 * '2-1i'.to_c # => (2-1i) # Values before and after '-': positive real, negative imaginary.
2338 *
2339 * Note that the suffixed character <tt>'i'</tt>
2340 * may instead be one of <tt>'I'</tt>, <tt>'j'</tt>, or <tt>'J'</tt>,
2341 * with the same effect.
2342 *
2343 * <b>Polar Coordinates</b>
2344 *
2345 * With separator <tt>'@'</tt>)
2346 * interprets the values as polar coordinates: magnitude and angle.
2347 *
2348 * '2@'.to_c.polar # => [2, 0.0] # Value before '@': magnitude only.
2349 * # Values before and after '@': magnitude and angle.
2350 * '2@1'.to_c.polar # => [2.0, 1.0]
2351 * "1.0@#{Math::PI/2}".to_c # => (0.0+1i)
2352 * "1.0@#{Math::PI}".to_c # => (-1+0.0i)
2353 * # Magnitude not given: defaults to zero.
2354 * '@'.to_c.polar # => [0, 0.0]
2355 * '@1'.to_c.polar # => [0, 0.0]
2356 *
2357 * '1.0@0'.to_c # => (1+0.0i)
2358 *
2359 * Note that in all cases, the suffixed character <tt>'i'</tt>
2360 * may instead be one of <tt>'I'</tt>, <tt>'j'</tt>, <tt>'J'</tt>,
2361 * with the same effect.
2362 *
2363 * See {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
2364 */
2365static VALUE
2366string_to_c(VALUE self)
2367{
2368 VALUE num;
2369
2370 rb_must_asciicompat(self);
2371
2372 (void)parse_comp(rb_str_fill_terminator(self, 1), FALSE, &num);
2373
2374 return num;
2375}
2376
2377static VALUE
2378to_complex(VALUE val)
2379{
2380 return rb_convert_type(val, T_COMPLEX, "Complex", "to_c");
2381}
2382
2383static VALUE
2384nucomp_convert(VALUE klass, VALUE a1, VALUE a2, int raise)
2385{
2386 if (NIL_P(a1) || NIL_P(a2)) {
2387 if (!raise) return Qnil;
2388 rb_cant_convert(Qnil, "Complex");
2389 }
2390
2391 if (RB_TYPE_P(a1, T_STRING)) {
2392 a1 = string_to_c_strict(a1, raise);
2393 if (NIL_P(a1)) return Qnil;
2394 }
2395
2396 if (RB_TYPE_P(a2, T_STRING)) {
2397 a2 = string_to_c_strict(a2, raise);
2398 if (NIL_P(a2)) return Qnil;
2399 }
2400
2401 if (RB_TYPE_P(a1, T_COMPLEX)) {
2402 {
2403 get_dat1(a1);
2404
2405 if (k_exact_zero_p(dat->imag))
2406 a1 = dat->real;
2407 }
2408 }
2409
2410 if (RB_TYPE_P(a2, T_COMPLEX)) {
2411 {
2412 get_dat1(a2);
2413
2414 if (k_exact_zero_p(dat->imag))
2415 a2 = dat->real;
2416 }
2417 }
2418
2419 if (RB_TYPE_P(a1, T_COMPLEX)) {
2420 if (UNDEF_P(a2) || (k_exact_zero_p(a2)))
2421 return a1;
2422 }
2423
2424 if (UNDEF_P(a2)) {
2425 if (k_numeric_p(a1) && !f_real_p(a1))
2426 return a1;
2427 /* should raise exception for consistency */
2428 if (!k_numeric_p(a1)) {
2429 if (!raise) {
2430 a1 = rb_protect(to_complex, a1, NULL);
2431 rb_set_errinfo(Qnil);
2432 return a1;
2433 }
2434 return to_complex(a1);
2435 }
2436 }
2437 else {
2438 if ((k_numeric_p(a1) && k_numeric_p(a2)) &&
2439 (!f_real_p(a1) || !f_real_p(a2)))
2440 return f_add(a1,
2441 f_mul(a2,
2442 f_complex_new_bang2(rb_cComplex, ZERO, ONE)));
2443 }
2444
2445 {
2446 int argc;
2447 VALUE argv2[2];
2448 argv2[0] = a1;
2449 if (UNDEF_P(a2)) {
2450 argv2[1] = Qnil;
2451 argc = 1;
2452 }
2453 else {
2454 if (!raise && !RB_INTEGER_TYPE_P(a2) && !RB_FLOAT_TYPE_P(a2) && !RB_TYPE_P(a2, T_RATIONAL))
2455 return Qnil;
2456 argv2[1] = a2;
2457 argc = 2;
2458 }
2459 return nucomp_s_new(argc, argv2, klass);
2460 }
2461}
2462
2463static VALUE
2464nucomp_s_convert(int argc, VALUE *argv, VALUE klass)
2465{
2466 VALUE a1, a2;
2467
2468 if (rb_scan_args(argc, argv, "11", &a1, &a2) == 1) {
2469 a2 = Qundef;
2470 }
2471
2472 return nucomp_convert(klass, a1, a2, TRUE);
2473}
2474
2475/*
2476 * call-seq:
2477 * abs2 -> real
2478 *
2479 * Returns the square of +self+.
2480 */
2481static VALUE
2482numeric_abs2(VALUE self)
2483{
2484 return f_mul(self, self);
2485}
2486
2487/*
2488 * call-seq:
2489 * arg -> 0 or Math::PI
2490 *
2491 * Returns zero if +self+ is positive, Math::PI otherwise.
2492 */
2493static VALUE
2494numeric_arg(VALUE self)
2495{
2496 if (f_positive_p(self))
2497 return INT2FIX(0);
2498 return DBL2NUM(M_PI);
2499}
2500
2501/*
2502 * call-seq:
2503 * rect -> array
2504 *
2505 * Returns array <tt>[self, 0]</tt>.
2506 */
2507static VALUE
2508numeric_rect(VALUE self)
2509{
2510 return rb_assoc_new(self, INT2FIX(0));
2511}
2512
2513/*
2514 * call-seq:
2515 * polar -> array
2516 *
2517 * Returns array <tt>[self.abs, self.arg]</tt>.
2518 */
2519static VALUE
2520numeric_polar(VALUE self)
2521{
2522 VALUE abs, arg;
2523
2524 if (RB_INTEGER_TYPE_P(self)) {
2525 abs = rb_int_abs(self);
2526 arg = numeric_arg(self);
2527 }
2528 else if (RB_FLOAT_TYPE_P(self)) {
2529 abs = rb_float_abs(self);
2530 arg = float_arg(self);
2531 }
2532 else if (RB_TYPE_P(self, T_RATIONAL)) {
2533 abs = rb_rational_abs(self);
2534 arg = numeric_arg(self);
2535 }
2536 else {
2537 abs = f_abs(self);
2538 arg = f_arg(self);
2539 }
2540 return rb_assoc_new(abs, arg);
2541}
2542
2543/*
2544 * call-seq:
2545 * arg -> 0 or Math::PI
2546 *
2547 * Returns 0 if +self+ is positive, Math::PI otherwise.
2548 */
2549static VALUE
2550float_arg(VALUE self)
2551{
2552 if (isnan(RFLOAT_VALUE(self)))
2553 return self;
2554 if (f_tpositive_p(self))
2555 return INT2FIX(0);
2556 return rb_const_get(rb_mMath, id_PI);
2557}
2558
2559/*
2560 * A \Complex object houses a pair of values,
2561 * given when the object is created as either <i>rectangular coordinates</i>
2562 * or <i>polar coordinates</i>.
2563 *
2564 * == Rectangular Coordinates
2565 *
2566 * The rectangular coordinates of a complex number
2567 * are called the _real_ and _imaginary_ parts;
2568 * see {Complex number definition}[https://en.wikipedia.org/wiki/Complex_number#Definition_and_basic_operations].
2569 *
2570 * You can create a \Complex object from rectangular coordinates with:
2571 *
2572 * - A {complex literal}[rdoc-ref:syntax/literals.rdoc@Complex+Literals].
2573 * - Method Complex.rect.
2574 * - Method Kernel#Complex, either with numeric arguments or with certain string arguments.
2575 * - Method String#to_c, for certain strings.
2576 *
2577 * Note that each of the stored parts may be a an instance one of the classes
2578 * Complex, Float, Integer, or Rational;
2579 * they may be retrieved:
2580 *
2581 * - Separately, with methods Complex#real and Complex#imaginary.
2582 * - Together, with method Complex#rect.
2583 *
2584 * The corresponding (computed) polar values may be retrieved:
2585 *
2586 * - Separately, with methods Complex#abs and Complex#arg.
2587 * - Together, with method Complex#polar.
2588 *
2589 * == Polar Coordinates
2590 *
2591 * The polar coordinates of a complex number
2592 * are called the _absolute_ and _argument_ parts;
2593 * see {Complex polar plane}[https://en.wikipedia.org/wiki/Complex_number#Polar_form].
2594 *
2595 * In this class, the argument part
2596 * in expressed {radians}[https://en.wikipedia.org/wiki/Radian]
2597 * (not {degrees}[https://en.wikipedia.org/wiki/Degree_(angle)]).
2598 *
2599 * You can create a \Complex object from polar coordinates with:
2600 *
2601 * - Method Complex.polar.
2602 * - Method Kernel#Complex, with certain string arguments.
2603 * - Method String#to_c, for certain strings.
2604 *
2605 * Note that each of the stored parts may be a an instance one of the classes
2606 * Complex, Float, Integer, or Rational;
2607 * they may be retrieved:
2608 *
2609 * - Separately, with methods Complex#abs and Complex#arg.
2610 * - Together, with method Complex#polar.
2611 *
2612 * The corresponding (computed) rectangular values may be retrieved:
2613 *
2614 * - Separately, with methods Complex#real and Complex#imag.
2615 * - Together, with method Complex#rect.
2616 *
2617 * == What's Here
2618 *
2619 * First, what's elsewhere:
2620 *
2621 * - Class \Complex inherits (directly or indirectly)
2622 * from classes {Numeric}[rdoc-ref:Numeric@Whats-Here]
2623 * and {Object}[rdoc-ref:Object@Whats-Here].
2624 * - Includes (indirectly) module {Comparable}[rdoc-ref:Comparable@Whats-Here].
2625 *
2626 * Here, class \Complex has methods for:
2627 *
2628 * === Creating \Complex Objects
2629 *
2630 * - ::polar: Returns a new \Complex object based on given polar coordinates.
2631 * - ::rect (and its alias ::rectangular):
2632 * Returns a new \Complex object based on given rectangular coordinates.
2633 *
2634 * === Querying
2635 *
2636 * - #abs (and its alias #magnitude): Returns the absolute value for +self+.
2637 * - #arg (and its aliases #angle and #phase):
2638 * Returns the argument (angle) for +self+ in radians.
2639 * - #denominator: Returns the denominator of +self+.
2640 * - #finite?: Returns whether both +self.real+ and +self.image+ are finite.
2641 * - #hash: Returns the integer hash value for +self+.
2642 * - #imag (and its alias #imaginary): Returns the imaginary value for +self+.
2643 * - #infinite?: Returns whether +self.real+ or +self.image+ is infinite.
2644 * - #numerator: Returns the numerator of +self+.
2645 * - #polar: Returns the array <tt>[self.abs, self.arg]</tt>.
2646 * - #inspect: Returns a string representation of +self+.
2647 * - #real: Returns the real value for +self+.
2648 * - #real?: Returns +false+; for compatibility with Numeric#real?.
2649 * - #rect (and its alias #rectangular):
2650 * Returns the array <tt>[self.real, self.imag]</tt>.
2651 *
2652 * === Comparing
2653 *
2654 * - #<=>: Returns whether +self+ is less than, equal to, or greater than the given argument.
2655 * - #==: Returns whether +self+ is equal to the given argument.
2656 *
2657 * === Converting
2658 *
2659 * - #rationalize: Returns a Rational object whose value is exactly
2660 * or approximately equivalent to that of <tt>self.real</tt>.
2661 * - #to_c: Returns +self+.
2662 * - #to_d: Returns the value as a BigDecimal object.
2663 * - #to_f: Returns the value of <tt>self.real</tt> as a Float, if possible.
2664 * - #to_i: Returns the value of <tt>self.real</tt> as an Integer, if possible.
2665 * - #to_r: Returns the value of <tt>self.real</tt> as a Rational, if possible.
2666 * - #to_s: Returns a string representation of +self+.
2667 *
2668 * === Performing Complex Arithmetic
2669 *
2670 * - #*: Returns the product of +self+ and the given numeric.
2671 * - #**: Returns +self+ raised to power of the given numeric.
2672 * - #+: Returns the sum of +self+ and the given numeric.
2673 * - #-: Returns the difference of +self+ and the given numeric.
2674 * - #-@: Returns the negation of +self+.
2675 * - #/: Returns the quotient of +self+ and the given numeric.
2676 * - #abs2: Returns square of the absolute value (magnitude) for +self+.
2677 * - #conj (and its alias #conjugate): Returns the conjugate of +self+.
2678 * - #fdiv: Returns <tt>Complex.rect(self.real/numeric, self.imag/numeric)</tt>.
2679 *
2680 * === Working with JSON
2681 *
2682 * - ::json_create: Returns a new \Complex object,
2683 * deserialized from the given serialized hash.
2684 * - #as_json: Returns a serialized hash constructed from +self+.
2685 * - #to_json: Returns a JSON string representing +self+.
2686 *
2687 * These methods are provided by the {JSON gem}[https://github.com/ruby/json]. To make these methods available:
2688 *
2689 * require 'json/add/complex'
2690 *
2691 */
2692void
2693Init_Complex(void)
2694{
2695 VALUE compat;
2696 id_abs = rb_intern_const("abs");
2697 id_arg = rb_intern_const("arg");
2698 id_real_p = rb_intern_const("real?");
2699 id_i_real = rb_intern_const("@real");
2700 id_i_imag = rb_intern_const("@image"); /* @image, not @imag */
2701 id_finite_p = rb_intern_const("finite?");
2702 id_infinite_p = rb_intern_const("infinite?");
2703 id_rationalize = rb_intern_const("rationalize");
2704 id_PI = rb_intern_const("PI");
2705
2706 rb_cComplex = rb_define_class("Complex", rb_cNumeric);
2707
2708 rb_define_alloc_func(rb_cComplex, nucomp_s_alloc);
2709 rb_undef_method(CLASS_OF(rb_cComplex), "allocate");
2710
2712
2713 rb_define_singleton_method(rb_cComplex, "rectangular", nucomp_s_new, -1);
2714 rb_define_singleton_method(rb_cComplex, "rect", nucomp_s_new, -1);
2715 rb_define_singleton_method(rb_cComplex, "polar", nucomp_s_polar, -1);
2716
2717 rb_define_global_function("Complex", nucomp_f_complex, -1);
2718
2719 rb_undef_methods_from(rb_cComplex, RCLASS_ORIGIN(rb_mComparable));
2722 rb_undef_method(rb_cComplex, "divmod");
2723 rb_undef_method(rb_cComplex, "floor");
2725 rb_undef_method(rb_cComplex, "modulo");
2726 rb_undef_method(rb_cComplex, "remainder");
2727 rb_undef_method(rb_cComplex, "round");
2729 rb_undef_method(rb_cComplex, "truncate");
2731
2732 rb_define_method(rb_cComplex, "real", rb_complex_real, 0);
2733 rb_define_method(rb_cComplex, "imaginary", rb_complex_imag, 0);
2734 rb_define_method(rb_cComplex, "imag", rb_complex_imag, 0);
2735
2736 rb_define_method(rb_cComplex, "-@", rb_complex_uminus, 0);
2737 rb_define_method(rb_cComplex, "+", rb_complex_plus, 1);
2738 rb_define_method(rb_cComplex, "-", rb_complex_minus, 1);
2739 rb_define_method(rb_cComplex, "*", rb_complex_mul, 1);
2740 rb_define_method(rb_cComplex, "/", rb_complex_div, 1);
2741 rb_define_method(rb_cComplex, "quo", nucomp_quo, 1);
2742 rb_define_method(rb_cComplex, "fdiv", nucomp_fdiv, 1);
2743 rb_define_method(rb_cComplex, "**", rb_complex_pow, 1);
2744
2745 rb_define_method(rb_cComplex, "==", nucomp_eqeq_p, 1);
2746 rb_define_method(rb_cComplex, "<=>", nucomp_cmp, 1);
2747 rb_define_method(rb_cComplex, "coerce", nucomp_coerce, 1);
2748
2749 rb_define_method(rb_cComplex, "abs", rb_complex_abs, 0);
2750 rb_define_method(rb_cComplex, "magnitude", rb_complex_abs, 0);
2751 rb_define_method(rb_cComplex, "abs2", nucomp_abs2, 0);
2752 rb_define_method(rb_cComplex, "arg", rb_complex_arg, 0);
2753 rb_define_method(rb_cComplex, "angle", rb_complex_arg, 0);
2754 rb_define_method(rb_cComplex, "phase", rb_complex_arg, 0);
2755 rb_define_method(rb_cComplex, "rectangular", nucomp_rect, 0);
2756 rb_define_method(rb_cComplex, "rect", nucomp_rect, 0);
2757 rb_define_method(rb_cComplex, "polar", nucomp_polar, 0);
2758 rb_define_method(rb_cComplex, "conjugate", rb_complex_conjugate, 0);
2759 rb_define_method(rb_cComplex, "conj", rb_complex_conjugate, 0);
2760
2761 rb_define_method(rb_cComplex, "real?", nucomp_real_p_m, 0);
2762
2763 rb_define_method(rb_cComplex, "numerator", nucomp_numerator, 0);
2764 rb_define_method(rb_cComplex, "denominator", nucomp_denominator, 0);
2765
2766 rb_define_method(rb_cComplex, "hash", nucomp_hash, 0);
2767 rb_define_method(rb_cComplex, "eql?", nucomp_eql_p, 1);
2768
2769 rb_define_method(rb_cComplex, "to_s", nucomp_to_s, 0);
2770 rb_define_method(rb_cComplex, "inspect", nucomp_inspect, 0);
2771
2772 rb_undef_method(rb_cComplex, "positive?");
2773 rb_undef_method(rb_cComplex, "negative?");
2774
2775 rb_define_method(rb_cComplex, "finite?", rb_complex_finite_p, 0);
2776 rb_define_method(rb_cComplex, "infinite?", rb_complex_infinite_p, 0);
2777
2778 rb_define_private_method(rb_cComplex, "marshal_dump", nucomp_marshal_dump, 0);
2779 /* :nodoc: */
2780 compat = rb_define_class_under(rb_cComplex, "compatible", rb_cObject);
2781 rb_define_private_method(compat, "marshal_load", nucomp_marshal_load, 1);
2782 rb_marshal_define_compat(rb_cComplex, compat, nucomp_dumper, nucomp_loader);
2783
2784 rb_define_method(rb_cComplex, "to_i", nucomp_to_i, 0);
2785 rb_define_method(rb_cComplex, "to_f", nucomp_to_f, 0);
2786 rb_define_method(rb_cComplex, "to_r", nucomp_to_r, 0);
2787 rb_define_method(rb_cComplex, "rationalize", nucomp_rationalize, -1);
2788 rb_define_method(rb_cComplex, "to_c", nucomp_to_c, 0);
2789 rb_define_method(rb_cNumeric, "to_c", numeric_to_c, 0);
2790
2791 rb_define_method(rb_cString, "to_c", string_to_c, 0);
2792
2793 rb_define_private_method(CLASS_OF(rb_cComplex), "convert", nucomp_s_convert, -1);
2794
2795 rb_define_method(rb_cNumeric, "abs2", numeric_abs2, 0);
2796 rb_define_method(rb_cNumeric, "arg", numeric_arg, 0);
2797 rb_define_method(rb_cNumeric, "angle", numeric_arg, 0);
2798 rb_define_method(rb_cNumeric, "phase", numeric_arg, 0);
2799 rb_define_method(rb_cNumeric, "rectangular", numeric_rect, 0);
2800 rb_define_method(rb_cNumeric, "rect", numeric_rect, 0);
2801 rb_define_method(rb_cNumeric, "polar", numeric_polar, 0);
2802
2803 rb_define_method(rb_cFloat, "arg", float_arg, 0);
2804 rb_define_method(rb_cFloat, "angle", float_arg, 0);
2805 rb_define_method(rb_cFloat, "phase", float_arg, 0);
2806
2807 /*
2808 * Equivalent
2809 * to <tt>Complex.rect(0, 1)</tt>:
2810 *
2811 * Complex::I # => (0+1i)
2812 *
2813 */
2814 rb_define_const(rb_cComplex, "I",
2815 f_complex_new_bang2(rb_cComplex, ZERO, ONE));
2816
2817#if !USE_FLONUM
2818 rb_vm_register_global_object(RFLOAT_0 = DBL2NUM(0.0));
2819#endif
2820
2821 rb_provide("complex.so"); /* for backward compatibility */
2822}
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
static int rb_isdigit(int c)
Our own locale-insensitive version of isdigit(3).
Definition ctype.h:302
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_private_method(klass, mid, func, arity)
Defines klass#mid and makes it private.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
Definition class.c:2707
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:3187
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
Definition value_type.h:59
#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 rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1684
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:131
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
#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
#define rb_usascii_str_new2
Old name of rb_usascii_str_new_cstr.
Definition string.h:1681
#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:405
#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:406
VALUE rb_eRangeError
RangeError exception.
Definition error.c:1435
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1431
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:468
VALUE rb_cRational
Rational class.
Definition rational.c:55
VALUE rb_convert_type(VALUE val, int type, const char *name, const char *mid)
Converts an object into another type.
Definition object.c:3219
VALUE rb_cComplex
Complex class.
Definition complex.c:40
VALUE rb_cObject
Object class.
Definition object.c:58
VALUE rb_mMath
Math module.
Definition math.c:28
VALUE rb_cInteger
Module class.
Definition numeric.c:202
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:3629
VALUE rb_cNumeric
Numeric class.
Definition numeric.c:200
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:232
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:657
VALUE rb_equal(VALUE lhs, VALUE rhs)
This function is an optimised version of calling #==.
Definition object.c:138
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:894
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:3585
VALUE rb_mComparable
Comparable module.
Definition compar.c:19
VALUE rb_cFloat
Float class.
Definition numeric.c:201
VALUE rb_String(VALUE val)
This is the logic behind Kernel#String.
Definition object.c:3855
VALUE rb_cString
String class.
Definition string.c:84
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1123
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:1081
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define rb_complex_new2(x, y)
Just another name of rb_complex_new.
Definition complex.h:77
#define rb_complex_new1(x)
Shorthand of x+0i.
Definition complex.h:74
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
void rb_provide(const char *feature)
Declares that the given feature is already provided by someone else.
Definition load.c:710
VALUE rb_num_coerce_cmp(VALUE lhs, VALUE rhs, ID op)
Identical to rb_num_coerce_bin(), except for return values.
Definition numeric.c:488
VALUE rb_num_coerce_bin(VALUE lhs, VALUE rhs, ID op)
Coerced binary operation.
Definition numeric.c:481
VALUE rb_rational_new(VALUE num, VALUE den)
Constructs a Rational, with reduction.
Definition rational.c:2006
st_index_t rb_memhash(const void *ptr, long len)
This is a universal hash function.
Definition random.c:1720
void rb_must_asciicompat(VALUE obj)
Asserts that the given string's encoding is (Ruby's definition of) ASCII compatible.
Definition string.c:2829
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:4117
VALUE rb_const_get(VALUE space, ID name)
Identical to rb_const_defined(), except it returns the actual defined value.
Definition variable.c:3408
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:2059
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:1578
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:3430
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:285
void rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE(*dumper)(VALUE), VALUE(*loader)(VALUE, VALUE))
Marshal format compatibility layer.
Definition marshal.c:137
void rb_copy_generic_ivar(VALUE clone, VALUE obj)
Copies the list of instance variables.
Definition variable.c:2253
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:50
#define RARRAY_AREF(a, i)
Definition rarray.h:402
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#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
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
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:425
static bool rb_integer_type_p(VALUE obj)
Queries if the object is an instance of rb_cInteger.
Definition value_type.h:204
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:376