A complex number can be represented as a paired real number with imaginary unit; a+bi. Where a is real part, b is imaginary part and i is imaginary unit. Real a equals complex a+0i mathematically.
In ruby, you can create complex object with Complex, ::rect, ::polar or to_c method.
Complex(1) #=> (1+0i) Complex(2, 3) #=> (2+3i) Complex.polar(2, 3) #=> (-1.9799849932008908+0.2822400161197344i) 3.to_c #=> (3+0i)
You can also create complex object from floating-point numbers or strings.
Complex(0.3) #=> (0.3+0i) Complex('0.3-0.5i') #=> (0.3-0.5i) Complex('2/3+3/4i') #=> ((2/3)+(3/4)*i) Complex('1@2') #=> (-0.4161468365471424+0.9092974268256817i) 0.3.to_c #=> (0.3+0i) '0.3-0.5i'.to_c #=> (0.3-0.5i) '2/3+3/4i'.to_c #=> ((2/3)+(3/4)*i) '1@2'.to_c #=> (-0.4161468365471424+0.9092974268256817i)
A complex object is either an exact or an inexact number.
Complex(1, 1) / 2 #=> ((1/2)+(1/2)*i) Complex(1, 1) / 2.0 #=> (0.5+0.5i)
static VALUE
nucomp_s_polar(VALUE klass, VALUE abs, VALUE arg)
{
return f_complex_polar(klass, abs, arg);
}
static VALUE
nucomp_s_new(int argc, VALUE *argv, VALUE klass)
{
VALUE real, imag;
switch (rb_scan_args(argc, argv, "11", &real, &imag)) {
case 1:
nucomp_real_check(real);
imag = ZERO;
break;
default:
nucomp_real_check(real);
nucomp_real_check(imag);
break;
}
return nucomp_s_canonicalize_internal(klass, real, imag);
}
static VALUE
nucomp_s_new(int argc, VALUE *argv, VALUE klass)
{
VALUE real, imag;
switch (rb_scan_args(argc, argv, "11", &real, &imag)) {
case 1:
nucomp_real_check(real);
imag = ZERO;
break;
default:
nucomp_real_check(real);
nucomp_real_check(imag);
break;
}
return nucomp_s_canonicalize_internal(klass, real, imag);
}
static VALUE
nucomp_mul(VALUE self, VALUE other)
{
if (k_complex_p(other)) {
VALUE real, imag;
get_dat2(self, other);
real = f_sub(f_mul(adat->real, bdat->real),
f_mul(adat->imag, bdat->imag));
imag = f_add(f_mul(adat->real, bdat->imag),
f_mul(adat->imag, bdat->real));
return f_complex_new2(CLASS_OF(self), real, imag);
}
if (k_numeric_p(other) && f_real_p(other)) {
get_dat1(self);
return f_complex_new2(CLASS_OF(self),
f_mul(dat->real, other),
f_mul(dat->imag, other));
}
return rb_num_coerce_bin(self, other, '*');
}
static VALUE
nucomp_expt(VALUE self, VALUE other)
{
if (k_exact_p(other) && f_zero_p(other))
return f_complex_new_bang1(CLASS_OF(self), ONE);
if (k_rational_p(other) && f_one_p(f_denominator(other)))
other = f_numerator(other); /* good? */
if (k_complex_p(other)) {
VALUE a, r, theta, ore, oim, nr, ntheta;
get_dat1(other);
a = f_polar(self);
r = RARRAY_PTR(a)[0];
theta = RARRAY_PTR(a)[1];
ore = dat->real;
oim = dat->imag;
nr = m_exp_bang(f_sub(f_mul(ore, m_log_bang(r)),
f_mul(oim, theta)));
ntheta = f_add(f_mul(theta, ore), f_mul(oim, m_log_bang(r)));
return f_complex_polar(CLASS_OF(self), nr, ntheta);
}
if (k_integer_p(other)) {
if (f_gt_p(other, ZERO)) {
VALUE x, z, n;
x = self;
z = x;
n = f_sub(other, ONE);
while (f_nonzero_p(n)) {
VALUE a;
while (a = f_divmod(n, TWO),
f_zero_p(RARRAY_PTR(a)[1])) {
get_dat1(x);
x = f_complex_new2(CLASS_OF(self),
f_sub(f_mul(dat->real, dat->real),
f_mul(dat->imag, dat->imag)),
f_mul(f_mul(TWO, dat->real), dat->imag));
n = RARRAY_PTR(a)[0];
}
z = f_mul(z, x);
n = f_sub(n, ONE);
}
return z;
}
return f_expt(f_div(f_to_r(ONE), self), f_negate(other));
}
if (k_numeric_p(other) && f_real_p(other)) {
VALUE a, r, theta;
a = f_polar(self);
r = RARRAY_PTR(a)[0];
theta = RARRAY_PTR(a)[1];
return f_complex_polar(CLASS_OF(self), f_expt(r, other),
f_mul(theta, other));
}
return rb_num_coerce_bin(self, other, id_expt);
}
static VALUE
nucomp_add(VALUE self, VALUE other)
{
if (k_complex_p(other)) {
VALUE real, imag;
get_dat2(self, other);
real = f_add(adat->real, bdat->real);
imag = f_add(adat->imag, bdat->imag);
return f_complex_new2(CLASS_OF(self), real, imag);
}
if (k_numeric_p(other) && f_real_p(other)) {
get_dat1(self);
return f_complex_new2(CLASS_OF(self),
f_add(dat->real, other), dat->imag);
}
return rb_num_coerce_bin(self, other, '+');
}
static VALUE
nucomp_sub(VALUE self, VALUE other)
{
if (k_complex_p(other)) {
VALUE real, imag;
get_dat2(self, other);
real = f_sub(adat->real, bdat->real);
imag = f_sub(adat->imag, bdat->imag);
return f_complex_new2(CLASS_OF(self), real, imag);
}
if (k_numeric_p(other) && f_real_p(other)) {
get_dat1(self);
return f_complex_new2(CLASS_OF(self),
f_sub(dat->real, other), dat->imag);
}
return rb_num_coerce_bin(self, other, '-');
}
static VALUE
nucomp_negate(VALUE self)
{
get_dat1(self);
return f_complex_new2(CLASS_OF(self),
f_negate(dat->real), f_negate(dat->imag));
}
static VALUE
nucomp_div(VALUE self, VALUE other)
{
if (k_complex_p(other)) {
get_dat2(self, other);
if (TYPE(adat->real) == T_FLOAT ||
TYPE(adat->imag) == T_FLOAT ||
TYPE(bdat->real) == T_FLOAT ||
TYPE(bdat->imag) == T_FLOAT) {
VALUE magn = m_hypot(bdat->real, bdat->imag);
VALUE tmp = f_complex_new_bang2(CLASS_OF(self),
f_div(bdat->real, magn),
f_div(bdat->imag, magn));
return f_div(f_mul(self, f_conj(tmp)), magn);
}
return f_div(f_mul(self, f_conj(other)), f_abs2(other));
}
if (k_numeric_p(other) && f_real_p(other)) {
get_dat1(self);
return f_complex_new2(CLASS_OF(self),
f_div(dat->real, other),
f_div(dat->imag, other));
}
return rb_num_coerce_bin(self, other, '/');
}
static VALUE
nucomp_equal_p(VALUE self, VALUE other)
{
if (k_complex_p(other)) {
get_dat2(self, other);
return f_boolcast(f_equal_p(adat->real, bdat->real) &&
f_equal_p(adat->imag, bdat->imag));
}
if (k_numeric_p(other) && f_real_p(other)) {
get_dat1(self);
return f_boolcast(f_equal_p(dat->real, other) && f_zero_p(dat->imag));
}
return f_equal_p(other, self);
}
static VALUE
nucomp_abs(VALUE self)
{
get_dat1(self);
return m_hypot(dat->real, dat->imag);
}
static VALUE
nucomp_abs2(VALUE self)
{
get_dat1(self);
return f_add(f_mul(dat->real, dat->real),
f_mul(dat->imag, dat->imag));
}
static VALUE
nucomp_arg(VALUE self)
{
get_dat1(self);
return m_atan2_bang(dat->imag, dat->real);
}
static VALUE
nucomp_arg(VALUE self)
{
get_dat1(self);
return m_atan2_bang(dat->imag, dat->real);
}
static VALUE
nucomp_coerce(VALUE self, VALUE other)
{
if (k_numeric_p(other) && f_real_p(other))
return rb_assoc_new(f_complex_new_bang1(CLASS_OF(self), other), self);
if (TYPE(other) == T_COMPLEX)
return rb_assoc_new(other, self);
rb_raise(rb_eTypeError, "%s can't be coerced into %s",
rb_obj_classname(other), rb_obj_classname(self));
return Qnil;
}
static VALUE
nucomp_conj(VALUE self)
{
get_dat1(self);
return f_complex_new2(CLASS_OF(self), dat->real, f_negate(dat->imag));
}
static VALUE
nucomp_conj(VALUE self)
{
get_dat1(self);
return f_complex_new2(CLASS_OF(self), dat->real, f_negate(dat->imag));
}
static VALUE
nucomp_denominator(VALUE self)
{
get_dat1(self);
return rb_lcm(f_denominator(dat->real), f_denominator(dat->imag));
}
static VALUE
nucomp_eql_p(VALUE self, VALUE other)
{
if (k_complex_p(other)) {
get_dat2(self, other);
return f_boolcast((CLASS_OF(adat->real) == CLASS_OF(bdat->real)) &&
(CLASS_OF(adat->imag) == CLASS_OF(bdat->imag)) &&
f_equal_p(self, other));
}
return Qfalse;
}
static VALUE
nucomp_exact_p(VALUE self)
{
get_dat1(self);
return f_boolcast(f_exact_p(dat->real) && f_exact_p(dat->imag));
}
static VALUE
nucomp_fdiv(VALUE self, VALUE other)
{
get_dat1(self);
return f_div(f_complex_new2(CLASS_OF(self),
f_to_f(dat->real),
f_to_f(dat->imag)), other);
}
static VALUE
nucomp_hash(VALUE self)
{
get_dat1(self);
return f_xor(f_hash(dat->real), f_hash(dat->imag));
}
static VALUE
nucomp_imag(VALUE self)
{
get_dat1(self);
return dat->imag;
}
static VALUE
nucomp_imag(VALUE self)
{
get_dat1(self);
return dat->imag;
}
static VALUE
nucomp_inexact_p(VALUE self)
{
return f_boolcast(!nucomp_exact_p(self));
}
static VALUE
nucomp_inspect(VALUE self)
{
VALUE s;
s = rb_usascii_str_new2("(");
rb_str_concat(s, nucomp_format(self, f_inspect));
rb_str_cat2(s, ")");
return s;
}
static VALUE
nucomp_abs(VALUE self)
{
get_dat1(self);
return m_hypot(dat->real, dat->imag);
}
static VALUE
nucomp_marshal_dump(VALUE self)
{
VALUE a;
get_dat1(self);
a = rb_assoc_new(dat->real, dat->imag);
rb_copy_generic_ivar(a, self);
return a;
}
static VALUE
nucomp_marshal_load(VALUE self, VALUE a)
{
get_dat1(self);
dat->real = RARRAY_PTR(a)[0];
dat->imag = RARRAY_PTR(a)[1];
rb_copy_generic_ivar(self, a);
return self;
}
static VALUE
nucomp_numerator(VALUE self)
{
VALUE cd;
get_dat1(self);
cd = f_denominator(self);
return f_complex_new2(CLASS_OF(self),
f_mul(f_numerator(dat->real),
f_div(cd, f_denominator(dat->real))),
f_mul(f_numerator(dat->imag),
f_div(cd, f_denominator(dat->imag))));
}
static VALUE
nucomp_arg(VALUE self)
{
get_dat1(self);
return m_atan2_bang(dat->imag, dat->real);
}
static VALUE
nucomp_polar(VALUE self)
{
return rb_assoc_new(f_abs(self), f_arg(self));
}
static VALUE
nucomp_div(VALUE self, VALUE other)
{
if (k_complex_p(other)) {
get_dat2(self, other);
if (TYPE(adat->real) == T_FLOAT ||
TYPE(adat->imag) == T_FLOAT ||
TYPE(bdat->real) == T_FLOAT ||
TYPE(bdat->imag) == T_FLOAT) {
VALUE magn = m_hypot(bdat->real, bdat->imag);
VALUE tmp = f_complex_new_bang2(CLASS_OF(self),
f_div(bdat->real, magn),
f_div(bdat->imag, magn));
return f_div(f_mul(self, f_conj(tmp)), magn);
}
return f_div(f_mul(self, f_conj(other)), f_abs2(other));
}
if (k_numeric_p(other) && f_real_p(other)) {
get_dat1(self);
return f_complex_new2(CLASS_OF(self),
f_div(dat->real, other),
f_div(dat->imag, other));
}
return rb_num_coerce_bin(self, other, '/');
}
static VALUE
nucomp_real(VALUE self)
{
get_dat1(self);
return dat->real;
}
static VALUE
nucomp_rect(VALUE self)
{
get_dat1(self);
return rb_assoc_new(dat->real, dat->imag);
}
static VALUE
nucomp_rect(VALUE self)
{
get_dat1(self);
return rb_assoc_new(dat->real, dat->imag);
}
static VALUE
nucomp_to_f(VALUE self)
{
get_dat1(self);
if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) {
VALUE s = f_to_s(self);
rb_raise(rb_eRangeError, "can't convert %s into Float",
StringValuePtr(s));
}
return f_to_f(dat->real);
}
static VALUE
nucomp_to_i(VALUE self)
{
get_dat1(self);
if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) {
VALUE s = f_to_s(self);
rb_raise(rb_eRangeError, "can't convert %s into Integer",
StringValuePtr(s));
}
return f_to_i(dat->real);
}
static VALUE
nucomp_to_r(VALUE self)
{
get_dat1(self);
if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) {
VALUE s = f_to_s(self);
rb_raise(rb_eRangeError, "can't convert %s into Rational",
StringValuePtr(s));
}
return f_to_r(dat->real);
}