Extended maintenance of Ruby 1.9.3 ended on February 23, 2015. Read more
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)
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); }
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); }
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); }
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, '*'); }
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); }
Performs addition.
static VALUE nucomp_add(VALUE self, VALUE other) { return f_addsub(self, other, f_add, '+'); }
Performs subtraction.
static VALUE nucomp_sub(VALUE self, VALUE other) { return f_addsub(self, other, f_sub, '-'); }
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)); }
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); }
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); }
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); }
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)); }
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); }
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); }
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)); }
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)); }
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)); }
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); }
Returns the imaginary part.
static VALUE nucomp_imag(VALUE self) { get_dat1(self); return dat->imag; }
Returns the imaginary part.
static VALUE nucomp_imag(VALUE self) { get_dat1(self); return dat->imag; }
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; }
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); }
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)))); }
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); }
Returns an array; [cmp.abs, cmp.arg].
static VALUE nucomp_polar(VALUE self) { return rb_assoc_new(f_abs(self), f_arg(self)); }
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); }
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); }
Returns the real part.
static VALUE nucomp_real(VALUE self) { get_dat1(self); return dat->real; }
Returns false.
static VALUE nucomp_false(VALUE self) { return Qfalse; }
Returns an array; [cmp.real, cmp.imag].
static VALUE nucomp_rect(VALUE self) { get_dat1(self); return rb_assoc_new(dat->real, dat->imag); }
Returns an array; [cmp.real, cmp.imag].
static VALUE nucomp_rect(VALUE self) { get_dat1(self); return rb_assoc_new(dat->real, dat->imag); }
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); }
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); }
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); }