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.
Complex object can be created as literal, and also by using Kernel#Complex, Complex::rect, Complex::polar or to_c method.
2+1i #=> (2+1i) 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)
The imaginary unit.
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);
        return nucomp_s_new_internal(klass, abs, ZERO);
      default:
        nucomp_real_check(abs);
        nucomp_real_check(arg);
        break;
    }
    if (RB_TYPE_P(abs, T_COMPLEX)) {
        get_dat1(abs);
        abs = dat->real;
    }
    if (RB_TYPE_P(arg, T_COMPLEX)) {
        get_dat1(arg);
        arg = dat->real;
    }
    return f_complex_polar(klass, abs, arg);
} 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_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);
} Returns a complex object which denotes the given rectangular form.
Complex.rectangular(1, 2) #=> (1+2i)
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);
} Returns a complex object which denotes the given rectangular form.
Complex.rectangular(1, 2) #=> (1+2i)
VALUE
rb_complex_mul(VALUE self, VALUE other)
{
    if (RB_TYPE_P(other, T_COMPLEX)) {
        VALUE real, imag;
        get_dat2(self, other);
        comp_mul(adat->real, adat->imag, bdat->real, bdat->imag, &real, &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_mul(dat->real, other),
                              f_mul(dat->imag, other));
    }
    return rb_num_coerce_bin(self, other, '*');
} Performs multiplication.
Complex(2, 3) * Complex(2, 3) #=> (-5+12i) Complex(900) * Complex(1) #=> (900+0i) Complex(-2, 9) * Complex(-9, 2) #=> (0-85i) Complex(9, 8) * 4 #=> (36+32i) Complex(20, 9) * 9.8 #=> (196.0+88.2i)
VALUE
rb_complex_pow(VALUE self, VALUE other)
{
    if (k_numeric_p(other) && k_exact_zero_p(other))
        return f_complex_new_bang1(CLASS_OF(self), ONE);
    if (RB_TYPE_P(other, T_RATIONAL) && RRATIONAL(other)->den == LONG2FIX(1))
        other = RRATIONAL(other)->num; /* c14n */
    if (RB_TYPE_P(other, T_COMPLEX)) {
        get_dat1(other);
        if (k_exact_zero_p(dat->imag))
            other = dat->real; /* c14n */
    }
    if (RB_TYPE_P(other, T_COMPLEX)) {
        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 (FIXNUM_P(other)) {
        long n = FIX2LONG(other);
        if (n == 0) {
            return nucomp_s_new_internal(CLASS_OF(self), ONE, ZERO);
        }
        if (n < 0) {
            self = f_reciprocal(self);
            other = rb_int_uminus(other);
            n = -n;
        }
        {
            get_dat1(self);
            VALUE xr = dat->real, xi = dat->imag, zr = xr, zi = xi;
            if (f_zero_p(xi)) {
                zr = rb_num_pow(zr, other);
            }
            else if (f_zero_p(xr)) {
                zi = rb_num_pow(zi, other);
                if (n & 2) zi = f_negate(zi);
                if (!(n & 1)) {
                    VALUE tmp = zr;
                    zr = zi;
                    zi = tmp;
                }
            }
            else {
                while (--n) {
                    long q, r;
                    for (; q = n / 2, r = n % 2, r == 0; n = q) {
                        VALUE tmp = f_sub(f_mul(xr, xr), f_mul(xi, xi));
                        xi = f_mul(f_mul(TWO, xr), xi);
                        xr = tmp;
                    }
                    comp_mul(zr, zi, xr, xi, &zr, &zi);
                }
            }
            return nucomp_s_new_internal(CLASS_OF(self), zr, zi);
        }
    }
    if (k_numeric_p(other) && f_real_p(other)) {
        VALUE r, theta;
        if (RB_TYPE_P(other, T_BIGNUM))
            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);
} Performs exponentiation.
Complex('i') ** 2              #=> (-1+0i)
Complex(-8) ** Rational(1, 3)  #=> (1.0000000000000002+1.7320508075688772i)
  VALUE
rb_complex_plus(VALUE self, VALUE other)
{
    if (RB_TYPE_P(other, T_COMPLEX)) {
        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, '+');
} Performs addition.
Complex(2, 3) + Complex(2, 3) #=> (4+6i) Complex(900) + Complex(1) #=> (901+0i) Complex(-2, 9) + Complex(-9, 2) #=> (-11+11i) Complex(9, 8) + 4 #=> (13+8i) Complex(20, 9) + 9.8 #=> (29.8+9i)
VALUE
rb_complex_minus(VALUE self, VALUE other)
{
    if (RB_TYPE_P(other, T_COMPLEX)) {
        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, '-');
} Performs subtraction.
Complex(2, 3) - Complex(2, 3) #=> (0+0i) Complex(900) - Complex(1) #=> (899+0i) Complex(-2, 9) - Complex(-9, 2) #=> (7+7i) Complex(9, 8) - 4 #=> (5+8i) Complex(20, 9) - 9.8 #=> (10.2+9i)
VALUE
rb_complex_uminus(VALUE self)
{
    get_dat1(self);
    return f_complex_new2(CLASS_OF(self),
                          f_negate(dat->real), f_negate(dat->imag));
} Returns negation of the value.
-Complex(1, 2) #=> (-1-2i)
VALUE
rb_complex_div(VALUE self, VALUE other)
{
    return f_divide(self, other, f_quo, id_quo);
} Performs division.
Complex(2, 3) / Complex(2, 3) #=> ((1/1)+(0/1)*i) Complex(900) / Complex(1) #=> ((900/1)+(0/1)*i) Complex(-2, 9) / Complex(-9, 2) #=> ((36/85)-(77/85)*i) Complex(9, 8) / 4 #=> ((9/4)+(2/1)*i) Complex(20, 9) / 9.8 #=> (2.0408163265306123+0.9183673469387754i)
static VALUE
nucomp_cmp(VALUE self, VALUE other)
{
    if (nucomp_real_p(self) && k_numeric_p(other)) {
        if (RB_TYPE_P(other, T_COMPLEX) && nucomp_real_p(other)) {
            get_dat2(self, other);
            return rb_funcall(adat->real, idCmp, 1, bdat->real);
        }
        else if (f_real_p(other)) {
            get_dat1(self);
            return rb_funcall(dat->real, idCmp, 1, other);
        }
    }
    return Qnil;
} If cmp's imaginary part is zero, and object is also a real number (or a Complex number where the imaginary part is zero), compare the real part of cmp to object. Otherwise, return nil.
Complex(2, 3) <=> Complex(2, 3) #=> nil Complex(2, 3) <=> 1 #=> nil Complex(2) <=> 1 #=> 1 Complex(2) <=> 2 #=> 0 Complex(2) <=> 3 #=> -1
static VALUE
nucomp_eqeq_p(VALUE self, VALUE other)
{
    if (RB_TYPE_P(other, T_COMPLEX)) {
        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_boolcast(f_eqeq_p(other, self));
} Returns true if cmp equals object numerically.
Complex(2, 3)  == Complex(2, 3)   #=> true
Complex(5)     == 5               #=> true
Complex(0)     == 0.0             #=> true
Complex('1/3') == 0.33            #=> false
Complex('1/2') == '1/2'           #=> false
  VALUE
rb_complex_abs(VALUE self)
{
    get_dat1(self);
    if (f_zero_p(dat->real)) {
        VALUE a = f_abs(dat->imag);
        if (RB_FLOAT_TYPE_P(dat->real) && !RB_FLOAT_TYPE_P(dat->imag))
            a = f_to_f(a);
        return a;
    }
    if (f_zero_p(dat->imag)) {
        VALUE a = f_abs(dat->real);
        if (!RB_FLOAT_TYPE_P(dat->real) && RB_FLOAT_TYPE_P(dat->imag))
            a = f_to_f(a);
        return a;
    }
    return rb_math_hypot(dat->real, dat->imag);
} Returns the absolute part of its polar form.
Complex(-1).abs #=> 1 Complex(3.0, -4.0).abs #=> 5.0
static VALUE
nucomp_abs2(VALUE self)
{
    get_dat1(self);
    return f_add(f_mul(dat->real, dat->real),
                 f_mul(dat->imag, dat->imag));
} Returns square of the absolute value.
Complex(-1).abs2 #=> 1 Complex(3.0, -4.0).abs2 #=> 25.0
Returns the angle part of its polar form.
Complex.polar(3, Math::PI/2).arg #=> 1.5707963267948966
VALUE
rb_complex_arg(VALUE self)
{
    get_dat1(self);
    return rb_math_atan2(dat->imag, dat->real);
} Returns the angle part of its polar form.
Complex.polar(3, Math::PI/2).arg #=> 1.5707963267948966
# File ext/json/lib/json/add/complex.rb, line 16
def as_json(*)
  {
    JSON.create_id => self.class.name,
    'r'            => real,
    'i'            => imag,
  }
end Returns a hash, that will be turned into a JSON object and represent this object.
Returns the complex conjugate.
Complex(1, 2).conjugate #=> (1-2i)
VALUE
rb_complex_conjugate(VALUE self)
{
    get_dat1(self);
    return f_complex_new2(CLASS_OF(self), dat->real, f_negate(dat->imag));
} Returns the complex conjugate.
Complex(1, 2).conjugate #=> (1-2i)
static VALUE
nucomp_denominator(VALUE self)
{
    get_dat1(self);
    return rb_lcm(f_denominator(dat->real), f_denominator(dat->imag));
} Returns the denominator (lcm of both denominator - real and imag).
See numerator.
static VALUE
nucomp_fdiv(VALUE self, VALUE other)
{
    return f_divide(self, other, f_fdiv, id_fdiv);
} Performs division as each part is a float, never returns a float.
Complex(11, 22).fdiv(3) #=> (3.6666666666666665+7.333333333333333i)
static VALUE
rb_complex_finite_p(VALUE self)
{
    get_dat1(self);
    if (f_finite_p(dat->real) && f_finite_p(dat->imag)) {
        return Qtrue;
    }
    return Qfalse;
} Returns true if cmp's real and imaginary parts are both finite numbers, otherwise returns false.
Returns the imaginary part.
Complex(7).imaginary #=> 0 Complex(9, -4).imaginary #=> -4
VALUE
rb_complex_imag(VALUE self)
{
    get_dat1(self);
    return dat->imag;
} Returns the imaginary part.
Complex(7).imaginary #=> 0 Complex(9, -4).imaginary #=> -4
static VALUE
rb_complex_infinite_p(VALUE self)
{
    get_dat1(self);
    if (NIL_P(f_infinite_p(dat->real)) && NIL_P(f_infinite_p(dat->imag))) {
        return Qnil;
    }
    return ONE;
} Returns 1 if cmp's real or imaginary part is an infinite number, otherwise returns nil.
For example: (1+1i).infinite? #=> nil (Float::INFINITY + 1i).infinite? #=> 1
static VALUE
nucomp_inspect(VALUE self)
{
    VALUE s;
    s = rb_usascii_str_new2("(");
    rb_str_concat(s, f_format(self, rb_inspect));
    rb_str_cat2(s, ")");
    return s;
} Returns the value as a string for inspection.
Complex(2).inspect                       #=> "(2+0i)"
Complex('-8/6').inspect                  #=> "((-4/3)+0i)"
Complex('1/2i').inspect                  #=> "(0+(1/2)*i)"
Complex(0, Float::INFINITY).inspect      #=> "(0+Infinity*i)"
Complex(Float::NAN, Float::NAN).inspect  #=> "(NaN+NaN*i)"
  Returns the absolute part of its polar form.
Complex(-1).abs #=> 1 Complex(3.0, -4.0).abs #=> 5.0
static VALUE
nucomp_numerator(VALUE self)
{
    VALUE cd;
    get_dat1(self);
    cd = nucomp_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))));
} Returns the numerator.
    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.
Returns the angle part of its polar form.
Complex.polar(3, Math::PI/2).arg #=> 1.5707963267948966
static VALUE
nucomp_polar(VALUE self)
{
    return rb_assoc_new(f_abs(self), f_arg(self));
} Returns an array; [cmp.abs, cmp.arg].
Complex(1, 2).polar #=> [2.23606797749979, 1.1071487177940904]
VALUE
rb_complex_div(VALUE self, VALUE other)
{
    return f_divide(self, other, f_quo, id_quo);
} Performs division.
Complex(2, 3) / Complex(2, 3) #=> ((1/1)+(0/1)*i) Complex(900) / Complex(1) #=> ((900/1)+(0/1)*i) Complex(-2, 9) / Complex(-9, 2) #=> ((36/85)-(77/85)*i) Complex(9, 8) / 4 #=> ((9/4)+(2/1)*i) Complex(20, 9) / 9.8 #=> (2.0408163265306123+0.9183673469387754i)
static VALUE
nucomp_rationalize(int argc, VALUE *argv, VALUE self)
{
    get_dat1(self);
    rb_check_arity(argc, 0, 1);
    if (!k_exact_zero_p(dat->imag)) {
       rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Rational",
                self);
    }
    return rb_funcallv(dat->real, id_rationalize, argc, argv);
} Returns the value as a rational if possible (the imaginary part should be exactly zero).
Complex(1.0/3, 0).rationalize #=> (1/3) Complex(1, 0.0).rationalize # RangeError Complex(1, 2).rationalize # RangeError
See to_r.
VALUE
rb_complex_real(VALUE self)
{
    get_dat1(self);
    return dat->real;
} Returns the real part.
Complex(7).real #=> 7 Complex(9, -4).real #=> 9
static VALUE
nucomp_false(VALUE self)
{
    return Qfalse;
} Returns false, even if the complex number has no imaginary part.
Returns a complex object which denotes the given rectangular form.
Complex.rectangular(1, 2) #=> (1+2i)
static VALUE
nucomp_rect(VALUE self)
{
    get_dat1(self);
    return rb_assoc_new(dat->real, dat->imag);
} Returns an array; [cmp.real, cmp.imag].
Complex(1, 2).rectangular #=> [1, 2]
static VALUE
nucomp_to_c(VALUE self)
{
    return self;
} Returns self.
Complex(2).to_c #=> (2+0i) Complex(-8, 6).to_c #=> (-8+6i)
# File ext/bigdecimal/lib/bigdecimal/util.rb, line 153
def to_d(*args)
  BigDecimal(self) unless self.imag.zero? # to raise eerror
  if args.length == 0
    case self.real
    when Rational
      BigDecimal(self.real) # to raise error
    end
  end
  self.real.to_d(*args)
end Returns the value as a BigDecimal.
The precision parameter is required for a rational complex number. This parameter is used to determine the number of significant digits for the result.
require 'bigdecimal' require 'bigdecimal/util' Complex(0.1234567, 0).to_d(4) # => 0.1235e0 Complex(Rational(22, 7), 0).to_d(3) # => 0.314e1
See also BigDecimal::new.
static VALUE
nucomp_to_f(VALUE self)
{
    get_dat1(self);
    if (!k_exact_zero_p(dat->imag)) {
        rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Float",
                 self);
    }
    return f_to_f(dat->real);
} Returns the value as a float if possible (the imaginary part should be exactly zero).
Complex(1, 0).to_f #=> 1.0 Complex(1, 0.0).to_f # RangeError Complex(1, 2).to_f # RangeError
static VALUE
nucomp_to_i(VALUE self)
{
    get_dat1(self);
    if (!k_exact_zero_p(dat->imag)) {
        rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Integer",
                 self);
    }
    return f_to_i(dat->real);
} Returns the value as an integer if possible (the imaginary part should be exactly zero).
Complex(1, 0).to_i #=> 1 Complex(1, 0.0).to_i # RangeError Complex(1, 2).to_i # RangeError
static VALUE
nucomp_to_r(VALUE self)
{
    get_dat1(self);
    if (!k_exact_zero_p(dat->imag)) {
        rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Rational",
                 self);
    }
    return f_to_r(dat->real);
} Returns the value as a rational if possible (the imaginary part should be exactly zero).
Complex(1, 0).to_r #=> (1/1) Complex(1, 0.0).to_r # RangeError Complex(1, 2).to_r # RangeError
See rationalize.
static VALUE
nucomp_to_s(VALUE self)
{
    return f_format(self, rb_String);
} Returns the value as a string.
Complex(2).to_s                       #=> "2+0i"
Complex('-8/6').to_s                  #=> "-4/3+0i"
Complex('1/2i').to_s                  #=> "0+1/2i"
Complex(0, Float::INFINITY).to_s      #=> "0+Infinity*i"
Complex(Float::NAN, Float::NAN).to_s  #=> "NaN+NaN*i"
  
    Ruby Core © 1993–2020 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.