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, Complex::rect, Complex::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.
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_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.
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.
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.
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);
}
Returns the value as a rational if possible. An optional argument eps is always ignored.
static VALUE
nucomp_rationalize(int argc, VALUE *argv, VALUE self)
{
rb_scan_args(argc, argv, "01", NULL);
return nucomp_to_r(self);
}
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);
}
Returns the value as a rational if possible.
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);
}