8#include "ruby/config.h"
11# define _USE_MATH_DEFINES 1
20#define ZERO INT2FIX(0)
24#define RFLOAT_0 DBL2NUM(0)
28#if defined(HAVE_SIGNBIT) && defined(__GNUC__) && defined(__sun) && \
35static ID id_abs, id_arg,
37 id_real_p, id_i_real, id_i_imag,
38 id_finite_p, id_infinite_p, id_rationalize,
42#define id_negate idUMinus
48#define f_boolcast(x) ((x) ? Qtrue : Qfalse)
54 return rb_funcall(x, id_##n, 0);\
59f_##n(VALUE x, VALUE y)\
61 return rb_funcall(x, id_##n, 1, y);\
64#define PRESERVE_SIGNEDZERO
127 if (x ==
ONE)
return y;
128 if (y ==
ONE)
return x;
133 if (y ==
ONE)
return x;
138 if (y ==
ONE)
return x;
142 if (y ==
ONE)
return x;
182 return numeric_arg(x);
188 return numeric_arg(x);
238static bool nucomp_real_p(
VALUE self);
253 return nucomp_real_p(x);
314#define f_positive_p(x) (!f_negative_p(x))
332#define f_nonzero_p(x) (!f_zero_p(x))
378#define k_exact_p(x) (!RB_FLOAT_TYPE_P(x))
380#define k_exact_zero_p(x) (k_exact_p(x) && f_zero_p(x))
383 struct RComplex *dat = RCOMPLEX(x)
385#define get_dat2(x,y) \
386 struct RComplex *adat = RCOMPLEX(x), *bdat = RCOMPLEX(y)
410 return nucomp_s_new_internal(
klass, x,
ZERO);
418 return nucomp_s_new_internal(
klass, x, y);
421#ifdef CANONICALIZATION_FOR_MATHN
425nucomp_canonicalization(
int f)
430#define canonicalization 0
434nucomp_real_check(
VALUE num)
439 if (!k_numeric_p(num) || !f_real_p(num))
447 int complex_r, complex_i;
448#ifdef CANONICALIZATION_FOR_MATHN
454 if (!complex_r && !complex_i) {
455 return nucomp_s_new_internal(
klass, real, imag);
457 else if (!complex_r) {
460 return nucomp_s_new_internal(
klass,
461 f_sub(real, dat->imag),
464 else if (!complex_i) {
467 return nucomp_s_new_internal(
klass,
469 f_add(dat->imag, imag));
474 return nucomp_s_new_internal(
klass,
475 f_sub(adat->real, bdat->imag),
476 f_add(adat->imag, bdat->real));
496 nucomp_real_check(real);
500 nucomp_real_check(real);
501 nucomp_real_check(imag);
505 return nucomp_s_canonicalize_internal(
klass, real, imag);
512 return nucomp_s_canonicalize_internal(
klass, x, y);
574m_##n##_bang(VALUE x)\
576 return rb_math_##n(x);\
596 return m_cos_bang(x);
600 f_mul(m_cos_bang(dat->real),
601 m_cosh_bang(dat->imag)),
603 m_sinh_bang(dat->imag)));
611 return m_sin_bang(x);
615 f_mul(m_sin_bang(dat->real),
616 m_cosh_bang(dat->imag)),
617 f_mul(m_cos_bang(dat->real),
618 m_sinh_bang(dat->imag)));
627 if (f_zero_p(x) || f_zero_p(y)) {
658 return nucomp_s_new_internal(
klass, x, y);
660 return nucomp_s_canonicalize_internal(
klass,
670 const double fr =
modf(ang, &fi);
671 int pos = fr == +0.5;
673 if (pos || fr == -0.5) {
674 if ((
modf(fi / 2.0, &fi) != fr) ^ pos)
abs = -
abs;
677 else if (fr == 0.0) {
705 nucomp_real_check(
abs);
709 nucomp_real_check(
abs);
710 nucomp_real_check(
arg);
761 return f_complex_new2(
CLASS_OF(
self),
785 real =
f_add(adat->real, bdat->real);
786 imag =
f_add(adat->imag, bdat->imag);
788 return f_complex_new2(
CLASS_OF(
self), real, imag);
790 if (k_numeric_p(other) && f_real_p(other)) {
793 return f_complex_new2(
CLASS_OF(
self),
794 f_add(dat->real, other), dat->imag);
819 real =
f_sub(adat->real, bdat->real);
820 imag =
f_sub(adat->imag, bdat->imag);
822 return f_complex_new2(
CLASS_OF(
self), real, imag);
824 if (k_numeric_p(other) && f_real_p(other)) {
827 return f_complex_new2(
CLASS_OF(
self),
828 f_sub(dat->real, other), dat->imag);
849 int arzero = f_zero_p(areal);
850 int aizero = f_zero_p(aimag);
851 int brzero = f_zero_p(breal);
852 int bizero = f_zero_p(bimag);
853 *real =
f_sub(safe_mul(areal, breal, arzero, brzero),
854 safe_mul(aimag, bimag, aizero, bizero));
855 *imag =
f_add(safe_mul(areal, bimag, arzero, bizero),
856 safe_mul(aimag, breal, aizero, brzero));
878 comp_mul(adat->real, adat->imag, bdat->real, bdat->imag, &real, &imag);
880 return f_complex_new2(
CLASS_OF(
self), real, imag);
882 if (k_numeric_p(other) && f_real_p(other)) {
885 return f_complex_new2(
CLASS_OF(
self),
886 f_mul(dat->real, other),
887 f_mul(dat->imag, other));
905 r = (*func)(bdat->imag, bdat->real);
907 x = (*func)(
f_add(adat->real,
f_mul(adat->imag, r)),
n);
908 y = (*func)(
f_sub(adat->imag,
f_mul(adat->real, r)),
n);
911 r = (*func)(bdat->real, bdat->imag);
913 x = (*func)(
f_add(
f_mul(adat->real, r), adat->imag),
n);
914 y = (*func)(
f_sub(
f_mul(adat->imag, r), adat->real),
n);
920 return f_complex_new2(
CLASS_OF(
self), x, y);
922 if (k_numeric_p(other) && f_real_p(other)) {
927 return f_complex_new2(
CLASS_OF(
self), x, y);
932#define rb_raise_zerodiv() rb_raise(rb_eZeroDivError, "divided by 0")
953#define nucomp_quo rb_complex_div
966 return f_divide(
self, other, f_fdiv,
id_fdiv);
1001 VALUE r, theta, nr, ntheta;
1006 theta = f_arg(
self);
1008 nr = m_exp_bang(
f_sub(
f_mul(dat->real, m_log_bang(r)),
1009 f_mul(dat->imag, theta)));
1011 f_mul(dat->imag, m_log_bang(r)));
1012 return f_complex_polar(
CLASS_OF(
self), nr, ntheta);
1026 VALUE xr = dat->real, xi = dat->imag, zr = xr, zi = xi;
1031 else if (f_zero_p(xr)) {
1044 for (; q =
n / 2, r =
n % 2, r == 0;
n = q) {
1049 comp_mul(zr, zi, xr, xi, &zr, &zi);
1052 return nucomp_s_new_internal(
CLASS_OF(
self), zr, zi);
1055 if (k_numeric_p(other) && f_real_p(other)) {
1059 rb_warn(
"in a**b, b may be too big");
1062 theta = f_arg(
self);
1065 f_mul(theta, other));
1088 return f_boolcast(f_eqeq_p(adat->real, bdat->real) &&
1089 f_eqeq_p(adat->imag, bdat->imag));
1091 if (k_numeric_p(other) && f_real_p(other)) {
1094 return f_boolcast(f_eqeq_p(dat->real, other) && f_zero_p(dat->imag));
1100nucomp_real_p(
VALUE self)
1103 return(f_zero_p(dat->imag) ?
true :
false);
1123 if (nucomp_real_p(
self) && k_numeric_p(other)) {
1128 else if (f_real_p(other)) {
1142 if (k_numeric_p(other) && f_real_p(other))
1165 if (f_zero_p(dat->real)) {
1171 if (f_zero_p(dat->imag)) {
1190nucomp_abs2(
VALUE self)
1194 f_mul(dat->imag, dat->imag));
1224nucomp_rect(
VALUE self)
1239nucomp_polar(
VALUE self)
1268nucomp_false(
VALUE self)
1282nucomp_denominator(
VALUE self)
1307nucomp_numerator(
VALUE self)
1313 cd = nucomp_denominator(
self);
1314 return f_complex_new2(
CLASS_OF(
self),
1323nucomp_hash(
VALUE self)
1346 f_eqeq_p(
self, other));
1359 return f_negative_p(x);
1363f_tpositive_p(
VALUE x)
1365 return !f_signbit(x);
1376 impos = f_tpositive_p(dat->imag);
1378 s = (*func)(dat->real);
1402nucomp_to_s(
VALUE self)
1420nucomp_inspect(
VALUE self)
1431#define FINITE_TYPE_P(v) (RB_INTEGER_TYPE_P(v) || RB_TYPE_P(v, T_RATIONAL))
1441rb_complex_finite_p(
VALUE self)
1445 if (f_finite_p(dat->real) && f_finite_p(dat->imag)) {
1464rb_complex_infinite_p(
VALUE self)
1468 if (
NIL_P(f_infinite_p(dat->real)) &&
NIL_P(f_infinite_p(dat->imag))) {
1476nucomp_dumper(
VALUE self)
1496nucomp_marshal_dump(
VALUE self)
1529 return nucomp_s_canonicalize_internal(
rb_cComplex, x, y);
1578nucomp_to_i(
VALUE self)
1586 return f_to_i(dat->real);
1601nucomp_to_f(
VALUE self)
1609 return f_to_f(dat->real);
1626nucomp_to_r(
VALUE self)
1634 return f_to_r(dat->real);
1674nucomp_to_c(
VALUE self)
1686nilclass_to_c(
VALUE self)
1698numeric_to_c(
VALUE self)
1708 return (c ==
'-' || c ==
'+');
1712read_sign(
const char **s,
1728 return isdigit((
unsigned char)c);
1732read_digits(
const char **s,
int strict,
1737 if (!isdecimal(**s))
1740 while (isdecimal(**s) || **s ==
'_') {
1758 }
while (**s ==
'_');
1765 return (c ==
'e' || c ==
'E');
1769read_num(
const char **s,
int strict,
1773 if (!read_digits(s, strict, b))
1781 if (!read_digits(s, strict, b)) {
1787 if (islettere(**s)) {
1792 if (!read_digits(s, strict, b)) {
1801read_den(
const char **s,
int strict,
1804 if (!read_digits(s, strict, b))
1810read_rat_nos(
const char **s,
int strict,
1813 if (!read_num(s, strict, b))
1819 if (!read_den(s, strict, b)) {
1828read_rat(
const char **s,
int strict,
1832 if (!read_rat_nos(s, strict, b))
1840 return (c ==
'i' || c ==
'I' ||
1841 c ==
'j' || c ==
'J');
1855read_comp(
const char **s,
int strict,
1856 VALUE *ret,
char **b)
1864 sign = read_sign(s, b);
1866 if (isimagunit(**s)) {
1868 num =
INT2FIX((sign ==
'-') ? -1 : + 1);
1873 if (!read_rat_nos(s, strict, b)) {
1882 if (isimagunit(**s)) {
1893 st = read_rat(s, strict, b);
1896 !isdecimal(*(bb +
strlen(bb) - 1))) {
1910 sign = read_sign(s, b);
1911 if (isimagunit(**s))
1912 num2 =
INT2FIX((sign ==
'-') ? -1 : + 1);
1914 if (!read_rat_nos(s, strict, b)) {
1921 if (!isimagunit(**s)) {
1937skip_ws(
const char **s)
1939 while (isspace((
unsigned char)**s))
1944parse_comp(
const char *s,
int strict,
VALUE *num)
1954 if (!read_comp(&s, strict, num, &b)) {
1970string_to_c_strict(
VALUE self,
int raise)
1980 if (!
raise)
return Qnil;
1993 if (!parse_comp(s, 1, &num)) {
1994 if (!
raise)
return Qnil;
2026string_to_c(
VALUE self)
2044 (
void)parse_comp(s, 0, &num);
2050to_complex(
VALUE val)
2059 if (!
raise)
return Qnil;
2064 a1 = string_to_c_strict(a1,
raise);
2069 a2 = string_to_c_strict(a2,
raise);
2097 if (k_numeric_p(a1) && !f_real_p(a1))
2100 if (!k_numeric_p(a1)) {
2103 return to_complex(a1);
2107 if ((k_numeric_p(a1) && k_numeric_p(a2)) &&
2108 (!f_real_p(a1) || !f_real_p(a2)))
2128 return nucomp_s_new(
argc, argv2,
klass);
2141 return nucomp_convert(
klass, a1, a2,
TRUE);
2153numeric_real(
VALUE self)
2166numeric_imag(
VALUE self)
2178numeric_abs2(
VALUE self)
2180 return f_mul(
self,
self);
2192numeric_arg(
VALUE self)
2207numeric_rect(
VALUE self)
2221numeric_polar(
VALUE self)
2227 arg = numeric_arg(
self);
2231 arg = float_arg(
self);
2235 arg = numeric_arg(
self);
2252numeric_conj(
VALUE self)
2266float_arg(
VALUE self)
2270 if (f_tpositive_p(
self))
2313#define rb_intern(str) rb_intern_const(str)
2324 id_rationalize =
rb_intern(
"rationalize");
#define k_exact_zero_p(x)
VALUE rb_complex_real(VALUE self)
VALUE rb_complex_uminus(VALUE self)
VALUE rb_complex_minus(VALUE self, VALUE other)
VALUE rb_Complex(VALUE x, VALUE y)
VALUE rb_complex_new_polar(VALUE x, VALUE y)
VALUE rb_complex_div(VALUE self, VALUE other)
VALUE rb_complex_plus(VALUE self, VALUE other)
VALUE rb_complex_raw(VALUE x, VALUE y)
VALUE rb_complex_pow(VALUE self, VALUE other)
VALUE rb_complex_arg(VALUE self)
VALUE rb_complex_abs(VALUE self)
VALUE rb_dbl_complex_new(double real, double imag)
Creates a Complex object.
VALUE rb_dbl_complex_new_polar_pi(double abs, double ang)
VALUE rb_flo_is_finite_p(VALUE num)
VALUE rb_complex_imag(VALUE self)
VALUE rb_flo_is_infinite_p(VALUE num)
VALUE rb_complex_new(VALUE x, VALUE y)
VALUE rb_complex_mul(VALUE self, VALUE other)
VALUE rb_complex_conjugate(VALUE self)
VALUE rb_complex_polar(VALUE x, VALUE y)
#define rb_cmpint(cmp, a, b)
VALUE rb_define_class(const char *, VALUE)
Defines a top-level class.
VALUE rb_define_class_under(VALUE, const char *, VALUE)
Defines a class under the namespace of outer.
void rb_undef_method(VALUE, const char *)
void rb_undef_methods_from(VALUE klass, VALUE super)
VALUE rb_cNilClass
NilClass class.
VALUE rb_cObject
Object class.
void rb_raise(VALUE exc, const char *fmt,...)
VALUE rb_protect(VALUE(*)(VALUE), VALUE, int *)
Protects a function call from potential global escapes from the function.
void rb_warn(const char *fmt,...)
VALUE rb_convert_type(VALUE, int, const char *, const char *)
Converts an object into another type.
int rb_opts_exception_p(VALUE opts, int default_value)
double rb_str_to_dbl(VALUE, int)
Parses a string representation of a floating point number.
VALUE rb_obj_class(VALUE)
Equivalent to Object#class in Ruby.
VALUE rb_inspect(VALUE)
Convenient wrapper of Object::inspect.
VALUE rb_equal(VALUE, VALUE)
Same as Object#===, case equality.
VALUE rb_obj_is_kind_of(VALUE, VALUE)
Determines if obj is a kind of c.
double rb_cstr_to_dbl(const char *, int)
Parses a string representation of a floating point number.
VALUE rb_String(VALUE)
Equivalent to Kernel#String in Ruby.