In Files

Complex

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)

Constants

I

Public Class Methods

polar(abs[, arg]) → complex click to toggle source

Returns a complex object which denotes the given polar form.

Complex.polar(3, 0)           #=> (3.0+0.0i)
Complex.polar(3, Math::PI/2)  #=> (1.836909530733566e-16+3.0i)
Complex.polar(3, Math::PI)    #=> (-3.0+3.673819061467132e-16i)
Complex.polar(3, -Math::PI/2) #=> (1.836909530733566e-16-3.0i)
 
               static VALUE
nucomp_s_polar(int argc, VALUE *argv, VALUE klass)
{
    VALUE abs, arg;

    switch (rb_scan_args(argc, argv, "11", &abs, &arg)) {
      case 1:
        nucomp_real_check(abs);
        arg = ZERO;
        break;
      default:
        nucomp_real_check(abs);
        nucomp_real_check(arg);
        break;
    }
    return f_complex_polar(klass, abs, arg);
}
            
rect(real[, imag]) → complex click to toggle source
rectangular(real[, imag]) → complex

Returns a complex object which denotes the given rectangular form.

 
               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);
}
            
rect(real[, imag]) → complex click to toggle source
rectangular(real[, imag]) → complex

Returns a complex object which denotes the given rectangular form.

 
               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);
}
            

Public Instance Methods

cmp * numeric → complex click to toggle source

Performs multiplication.

 
               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, '*');
}
            
cmp ** numeric → complex click to toggle source

Performs exponentiation.

For example:

Complex('i') ** 2             #=> (-1+0i)
Complex(-8) ** Rational(1,3)  #=> (1.0000000000000002+1.7320508075688772i)
 
               static VALUE
nucomp_expt(VALUE self, VALUE other)
{
    if (k_numeric_p(other) && k_exact_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); /* c14n */

    if (k_complex_p(other)) {
        get_dat1(other);

        if (k_exact_zero_p(dat->imag))
            other = dat->real; /* c14n */
    }

    if (k_complex_p(other)) {
        VALUE r, theta, nr, ntheta;

        get_dat1(other);

        r = f_abs(self);
        theta = f_arg(self);

        nr = m_exp_bang(f_sub(f_mul(dat->real, m_log_bang(r)),
                              f_mul(dat->imag, theta)));
        ntheta = f_add(f_mul(theta, dat->real),
                       f_mul(dat->imag, m_log_bang(r)));
        return f_complex_polar(CLASS_OF(self), nr, ntheta);
    }
    if (k_fixnum_p(other)) {
        if (f_gt_p(other, ZERO)) {
            VALUE x, z;
            long n;

            x = self;
            z = x;
            n = FIX2LONG(other) - 1;

            while (n) {
                long q, r;

                while (1) {
                    get_dat1(x);

                    q = n / 2;
                    r = n % 2;

                    if (r)
                        break;

                    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 = q;
                }
                z = f_mul(z, x);
                n--;
            }
            return z;
        }
        return f_expt(f_reciprocal(self), f_negate(other));
    }
    if (k_numeric_p(other) && f_real_p(other)) {
        VALUE r, theta;

        if (k_bignum_p(other))
            rb_warn("in a**b, b may be too big");

        r = f_abs(self);
        theta = f_arg(self);

        return f_complex_polar(CLASS_OF(self), f_expt(r, other),
                               f_mul(theta, other));
    }
    return rb_num_coerce_bin(self, other, id_expt);
}
            
cmp + numeric → complex click to toggle source

Performs addition.

 
               static VALUE
nucomp_add(VALUE self, VALUE other)
{
    return f_addsub(self, other, f_add, '+');
}
            
cmp - numeric → complex click to toggle source

Performs subtraction.

 
               static VALUE
nucomp_sub(VALUE self, VALUE other)
{
    return f_addsub(self, other, f_sub, '-');
}
            
-cmp → complex click to toggle source

Returns negation of the value.

 
               static VALUE
nucomp_negate(VALUE self)
{
  get_dat1(self);
  return f_complex_new2(CLASS_OF(self),
                        f_negate(dat->real), f_negate(dat->imag));
}
            
cmp / numeric → complex click to toggle source
quo(numeric) → complex

Performs division.

For example:

Complex(10.0) / 3  #=> (3.3333333333333335+(0/1)*i)
Complex(10)   / 3  #=> ((10/3)+(0/1)*i)  # not (3+0i)
 
               static VALUE
nucomp_div(VALUE self, VALUE other)
{
    return f_divide(self, other, f_quo, id_quo);
}
            
cmp == object → true or false click to toggle source

Returns true if cmp equals object numerically.

 
               static VALUE
nucomp_eqeq_p(VALUE self, VALUE other)
{
    if (k_complex_p(other)) {
        get_dat2(self, other);

        return f_boolcast(f_eqeq_p(adat->real, bdat->real) &&
                          f_eqeq_p(adat->imag, bdat->imag));
    }
    if (k_numeric_p(other) && f_real_p(other)) {
        get_dat1(self);

        return f_boolcast(f_eqeq_p(dat->real, other) && f_zero_p(dat->imag));
    }
    return f_eqeq_p(other, self);
}
            
abs → real click to toggle source
magnitude → real

Returns the absolute part of its polar form.

 
               static VALUE
nucomp_abs(VALUE self)
{
    get_dat1(self);

    if (f_zero_p(dat->real)) {
        VALUE a = f_abs(dat->imag);
        if (k_float_p(dat->real) && !k_float_p(dat->imag))
            a = f_to_f(a);
        return a;
    }
    if (f_zero_p(dat->imag)) {
        VALUE a = f_abs(dat->real);
        if (!k_float_p(dat->real) && k_float_p(dat->imag))
            a = f_to_f(a);
        return a;
    }
    return m_hypot(dat->real, dat->imag);
}
            
abs2 → real click to toggle source

Returns square of the absolute value.

 
               static VALUE
nucomp_abs2(VALUE self)
{
    get_dat1(self);
    return f_add(f_mul(dat->real, dat->real),
                 f_mul(dat->imag, dat->imag));
}
            
arg → float click to toggle source
angle → float
phase → float

Returns the angle part of its polar form.

Complex.polar(3, Math::PI/2).arg #=> 1.5707963267948966
 
               static VALUE
nucomp_arg(VALUE self)
{
    get_dat1(self);
    return m_atan2_bang(dat->imag, dat->real);
}
            
arg → float click to toggle source
angle → float
phase → float

Returns the angle part of its polar form.

Complex.polar(3, Math::PI/2).arg #=> 1.5707963267948966
 
               static VALUE
nucomp_arg(VALUE self)
{
    get_dat1(self);
    return m_atan2_bang(dat->imag, dat->real);
}
            
conj → complex click to toggle source
conjugate → complex

Returns the complex conjugate.

 
               static VALUE
nucomp_conj(VALUE self)
{
    get_dat1(self);
    return f_complex_new2(CLASS_OF(self), dat->real, f_negate(dat->imag));
}
            
conj → complex click to toggle source
conjugate → complex

Returns the complex conjugate.

 
               static VALUE
nucomp_conj(VALUE self)
{
    get_dat1(self);
    return f_complex_new2(CLASS_OF(self), dat->real, f_negate(dat->imag));
}
            
denominator → integer click to toggle source

Returns the denominator (lcm of both denominator - real and imag).

See numerator.

 
               static VALUE
nucomp_denominator(VALUE self)
{
    get_dat1(self);
    return rb_lcm(f_denominator(dat->real), f_denominator(dat->imag));
}
            
fdiv(numeric) → complex click to toggle source

Performs division as each part is a float, never returns a float.

For example:

Complex(11,22).fdiv(3)  #=> (3.6666666666666665+7.333333333333333i)
 
               static VALUE
nucomp_fdiv(VALUE self, VALUE other)
{
    return f_divide(self, other, f_fdiv, id_fdiv);
}
            
imag → real click to toggle source
imaginary → real

Returns the imaginary part.

 
               static VALUE
nucomp_imag(VALUE self)
{
    get_dat1(self);
    return dat->imag;
}
            
imag → real click to toggle source
imaginary → real

Returns the imaginary part.

 
               static VALUE
nucomp_imag(VALUE self)
{
    get_dat1(self);
    return dat->imag;
}
            
inspect → string click to toggle source

Returns the value as a string for inspection.

 
               static VALUE
nucomp_inspect(VALUE self)
{
    VALUE s;

    s = rb_usascii_str_new2("(");
    rb_str_concat(s, f_format(self, f_inspect));
    rb_str_cat2(s, ")");

    return s;
}
            
abs → real click to toggle source
magnitude → real

Returns the absolute part of its polar form.

 
               static VALUE
nucomp_abs(VALUE self)
{
    get_dat1(self);

    if (f_zero_p(dat->real)) {
        VALUE a = f_abs(dat->imag);
        if (k_float_p(dat->real) && !k_float_p(dat->imag))
            a = f_to_f(a);
        return a;
    }
    if (f_zero_p(dat->imag)) {
        VALUE a = f_abs(dat->real);
        if (!k_float_p(dat->real) && k_float_p(dat->imag))
            a = f_to_f(a);
        return a;
    }
    return m_hypot(dat->real, dat->imag);
}
            
numerator → numeric click to toggle source

Returns the numerator.

For example:

    1   2       3+4i  <-  numerator
    - + -i  ->  ----
    2   3        6    <-  denominator

c = Complex('1/2+2/3i')  #=> ((1/2)+(2/3)*i)
n = c.numerator          #=> (3+4i)
d = c.denominator        #=> 6
n / d                    #=> ((1/2)+(2/3)*i)
Complex(Rational(n.real, d), Rational(n.imag, d))
                         #=> ((1/2)+(2/3)*i)

See denominator.

 
               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))));
}
            
arg → float click to toggle source
angle → float
phase → float

Returns the angle part of its polar form.

Complex.polar(3, Math::PI/2).arg #=> 1.5707963267948966
 
               static VALUE
nucomp_arg(VALUE self)
{
    get_dat1(self);
    return m_atan2_bang(dat->imag, dat->real);
}
            
polar → array click to toggle source

Returns an array; [cmp.abs, cmp.arg].

 
               static VALUE
nucomp_polar(VALUE self)
{
    return rb_assoc_new(f_abs(self), f_arg(self));
}
            
cmp / numeric → complex click to toggle source
quo(numeric) → complex

Performs division.

For example:

Complex(10.0) / 3  #=> (3.3333333333333335+(0/1)*i)
Complex(10)   / 3  #=> ((10/3)+(0/1)*i)  # not (3+0i)
 
               static VALUE
nucomp_div(VALUE self, VALUE other)
{
    return f_divide(self, other, f_quo, id_quo);
}
            
rationalize([eps]) → rational click to toggle source

If the imaginary part is exactly 0, returns the real part as a Rational, otherwise a RangeError is raised.

 
               static VALUE
nucomp_rationalize(int argc, VALUE *argv, VALUE self)
{
    get_dat1(self);

    rb_scan_args(argc, argv, "01", NULL);

    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 rb_funcall2(dat->real, rb_intern("rationalize"), argc, argv);
}
            
real → real click to toggle source

Returns the real part.

 
               static VALUE
nucomp_real(VALUE self)
{
    get_dat1(self);
    return dat->real;
}
            
real? → false click to toggle source

Returns false.

 
               static VALUE
nucomp_false(VALUE self)
{
    return Qfalse;
}
            
rect → array click to toggle source
rectangular → array

Returns an array; [cmp.real, cmp.imag].

 
               static VALUE
nucomp_rect(VALUE self)
{
    get_dat1(self);
    return rb_assoc_new(dat->real, dat->imag);
}
            
rect → array click to toggle source
rectangular → array

Returns an array; [cmp.real, cmp.imag].

 
               static VALUE
nucomp_rect(VALUE self)
{
    get_dat1(self);
    return rb_assoc_new(dat->real, dat->imag);
}
            
to_f → float click to toggle source

Returns the value as a float if possible.

 
               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);
}
            
to_i → integer click to toggle source

Returns the value as an integer if possible.

 
               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);
}
            
to_r → rational click to toggle source

If the imaginary part is exactly 0, returns the real part as a Rational, otherwise a RangeError is raised.

 
               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);
}
            
to_s → string click to toggle source

Returns the value as a string.

 
               static VALUE
nucomp_to_s(VALUE self)
{
    return f_format(self, f_to_s);
}
            
conj → complex click to toggle source
conjugate → complex

Returns the complex conjugate.

 
               static VALUE
nucomp_conj(VALUE self)
{
    get_dat1(self);
    return f_complex_new2(CLASS_OF(self), dat->real, f_negate(dat->imag));
}
            

Commenting is here to help enhance the documentation. For example, sample code, or clarification of the documentation.

If you have questions about Ruby or the documentation, please post to one of the Ruby mailing lists. You will get better, faster, help that way.

If you wish to post a correction of the docs, please do so, but also file bug report so that it can be corrected for the next release. Thank you.

blog comments powered by Disqus