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)
static VALUE
nucomp_s_polar(VALUE klass, VALUE abs, VALUE arg)
{
return f_complex_polar(klass, abs, arg);
}
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);
}
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);
}
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, '*');
}
static VALUE
nucomp_expt(VALUE self, VALUE other)
{
if (k_exact_p(other) && f_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); /* good? */
if (k_complex_p(other)) {
VALUE a, r, theta, ore, oim, nr, ntheta;
get_dat1(other);
a = f_polar(self);
r = RARRAY_PTR(a)[0];
theta = RARRAY_PTR(a)[1];
ore = dat->real;
oim = dat->imag;
nr = m_exp_bang(f_sub(f_mul(ore, m_log_bang(r)),
f_mul(oim, theta)));
ntheta = f_add(f_mul(theta, ore), f_mul(oim, m_log_bang(r)));
return f_complex_polar(CLASS_OF(self), nr, ntheta);
}
if (k_integer_p(other)) {
if (f_gt_p(other, ZERO)) {
VALUE x, z, n;
x = self;
z = x;
n = f_sub(other, ONE);
while (f_nonzero_p(n)) {
VALUE a;
while (a = f_divmod(n, TWO),
f_zero_p(RARRAY_PTR(a)[1])) {
get_dat1(x);
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 = RARRAY_PTR(a)[0];
}
z = f_mul(z, x);
n = f_sub(n, ONE);
}
return z;
}
return f_expt(f_div(f_to_r(ONE), self), f_negate(other));
}
if (k_numeric_p(other) && f_real_p(other)) {
VALUE a, r, theta;
a = f_polar(self);
r = RARRAY_PTR(a)[0];
theta = RARRAY_PTR(a)[1];
return f_complex_polar(CLASS_OF(self), f_expt(r, other),
f_mul(theta, other));
}
return rb_num_coerce_bin(self, other, id_expt);
}
static VALUE
nucomp_add(VALUE self, VALUE other)
{
if (k_complex_p(other)) {
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, '+');
}
static VALUE
nucomp_sub(VALUE self, VALUE other)
{
if (k_complex_p(other)) {
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, '-');
}
static VALUE
nucomp_negate(VALUE self)
{
get_dat1(self);
return f_complex_new2(CLASS_OF(self),
f_negate(dat->real), f_negate(dat->imag));
}
static VALUE
nucomp_div(VALUE self, VALUE other)
{
if (k_complex_p(other)) {
get_dat2(self, other);
if (TYPE(adat->real) == T_FLOAT ||
TYPE(adat->imag) == T_FLOAT ||
TYPE(bdat->real) == T_FLOAT ||
TYPE(bdat->imag) == T_FLOAT) {
VALUE magn = m_hypot(bdat->real, bdat->imag);
VALUE tmp = f_complex_new_bang2(CLASS_OF(self),
f_div(bdat->real, magn),
f_div(bdat->imag, magn));
return f_div(f_mul(self, f_conj(tmp)), magn);
}
return f_div(f_mul(self, f_conj(other)), f_abs2(other));
}
if (k_numeric_p(other) && f_real_p(other)) {
get_dat1(self);
return f_complex_new2(CLASS_OF(self),
f_div(dat->real, other),
f_div(dat->imag, other));
}
return rb_num_coerce_bin(self, other, '/');
}
static VALUE
nucomp_equal_p(VALUE self, VALUE other)
{
if (k_complex_p(other)) {
get_dat2(self, other);
return f_boolcast(f_equal_p(adat->real, bdat->real) &&
f_equal_p(adat->imag, bdat->imag));
}
if (k_numeric_p(other) && f_real_p(other)) {
get_dat1(self);
return f_boolcast(f_equal_p(dat->real, other) && f_zero_p(dat->imag));
}
return f_equal_p(other, self);
}
static VALUE
nucomp_abs(VALUE self)
{
get_dat1(self);
return m_hypot(dat->real, dat->imag);
}
static VALUE
nucomp_abs2(VALUE self)
{
get_dat1(self);
return f_add(f_mul(dat->real, dat->real),
f_mul(dat->imag, dat->imag));
}
static VALUE
nucomp_arg(VALUE self)
{
get_dat1(self);
return m_atan2_bang(dat->imag, dat->real);
}
static VALUE
nucomp_arg(VALUE self)
{
get_dat1(self);
return m_atan2_bang(dat->imag, dat->real);
}
static VALUE
nucomp_coerce(VALUE self, VALUE other)
{
if (k_numeric_p(other) && f_real_p(other))
return rb_assoc_new(f_complex_new_bang1(CLASS_OF(self), other), self);
if (TYPE(other) == T_COMPLEX)
return rb_assoc_new(other, self);
rb_raise(rb_eTypeError, "%s can't be coerced into %s",
rb_obj_classname(other), rb_obj_classname(self));
return Qnil;
}
static VALUE
nucomp_conj(VALUE self)
{
get_dat1(self);
return f_complex_new2(CLASS_OF(self), dat->real, f_negate(dat->imag));
}
static VALUE
nucomp_conj(VALUE self)
{
get_dat1(self);
return f_complex_new2(CLASS_OF(self), dat->real, f_negate(dat->imag));
}
static VALUE
nucomp_denominator(VALUE self)
{
get_dat1(self);
return rb_lcm(f_denominator(dat->real), f_denominator(dat->imag));
}
static VALUE
nucomp_eql_p(VALUE self, VALUE other)
{
if (k_complex_p(other)) {
get_dat2(self, other);
return f_boolcast((CLASS_OF(adat->real) == CLASS_OF(bdat->real)) &&
(CLASS_OF(adat->imag) == CLASS_OF(bdat->imag)) &&
f_equal_p(self, other));
}
return Qfalse;
}
static VALUE
nucomp_exact_p(VALUE self)
{
get_dat1(self);
return f_boolcast(f_exact_p(dat->real) && f_exact_p(dat->imag));
}
static VALUE
nucomp_fdiv(VALUE self, VALUE other)
{
get_dat1(self);
return f_div(f_complex_new2(CLASS_OF(self),
f_to_f(dat->real),
f_to_f(dat->imag)), other);
}
static VALUE
nucomp_hash(VALUE self)
{
get_dat1(self);
return f_xor(f_hash(dat->real), f_hash(dat->imag));
}
static VALUE
nucomp_imag(VALUE self)
{
get_dat1(self);
return dat->imag;
}
static VALUE
nucomp_imag(VALUE self)
{
get_dat1(self);
return dat->imag;
}
static VALUE
nucomp_inexact_p(VALUE self)
{
return f_boolcast(!nucomp_exact_p(self));
}
static VALUE
nucomp_inspect(VALUE self)
{
VALUE s;
s = rb_usascii_str_new2("(");
rb_str_concat(s, nucomp_format(self, f_inspect));
rb_str_cat2(s, ")");
return s;
}
static VALUE
nucomp_abs(VALUE self)
{
get_dat1(self);
return m_hypot(dat->real, dat->imag);
}
static VALUE
nucomp_marshal_dump(VALUE self)
{
VALUE a;
get_dat1(self);
a = rb_assoc_new(dat->real, dat->imag);
rb_copy_generic_ivar(a, self);
return a;
}
static VALUE
nucomp_marshal_load(VALUE self, VALUE a)
{
get_dat1(self);
dat->real = RARRAY_PTR(a)[0];
dat->imag = RARRAY_PTR(a)[1];
rb_copy_generic_ivar(self, a);
return self;
}
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))));
}
static VALUE
nucomp_arg(VALUE self)
{
get_dat1(self);
return m_atan2_bang(dat->imag, dat->real);
}
static VALUE
nucomp_polar(VALUE self)
{
return rb_assoc_new(f_abs(self), f_arg(self));
}
static VALUE
nucomp_div(VALUE self, VALUE other)
{
if (k_complex_p(other)) {
get_dat2(self, other);
if (TYPE(adat->real) == T_FLOAT ||
TYPE(adat->imag) == T_FLOAT ||
TYPE(bdat->real) == T_FLOAT ||
TYPE(bdat->imag) == T_FLOAT) {
VALUE magn = m_hypot(bdat->real, bdat->imag);
VALUE tmp = f_complex_new_bang2(CLASS_OF(self),
f_div(bdat->real, magn),
f_div(bdat->imag, magn));
return f_div(f_mul(self, f_conj(tmp)), magn);
}
return f_div(f_mul(self, f_conj(other)), f_abs2(other));
}
if (k_numeric_p(other) && f_real_p(other)) {
get_dat1(self);
return f_complex_new2(CLASS_OF(self),
f_div(dat->real, other),
f_div(dat->imag, other));
}
return rb_num_coerce_bin(self, other, '/');
}
static VALUE
nucomp_real(VALUE self)
{
get_dat1(self);
return dat->real;
}
static VALUE
nucomp_rect(VALUE self)
{
get_dat1(self);
return rb_assoc_new(dat->real, dat->imag);
}
static VALUE
nucomp_rect(VALUE self)
{
get_dat1(self);
return rb_assoc_new(dat->real, dat->imag);
}
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);
}
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);
}
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, code samples, 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.
If you want to help improve the Ruby documentation, please see Improve the docs, or visit Documenting-ruby.org.