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