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