# remcopeereboom's solution

## to Complex Numbers in the Ruby Track

Published at Aug 30 2018 · 0 comments
Instructions
Test suite
Solution

#### Note:

This exercise has changed since this solution was written.

A complex number is a number in the form `a + b * i` where `a` and `b` are real and `i` satisfies `i^2 = -1`.

`a` is called the real part and `b` is called the imaginary part of `z`. The conjugate of the number `a + b * i` is the number `a - b * i`. The absolute value of a complex number `z = a + b * i` is a real number `|z| = sqrt(a^2 + b^2)`. The square of the absolute value `|z|^2` is the result of multiplication of `z` by its complex conjugate.

The sum/difference of two complex numbers involves adding/subtracting their real and imaginary parts separately: `(a + i * b) + (c + i * d) = (a + c) + (b + d) * i`, `(a + i * b) - (c + i * d) = (a - c) + (b - d) * i`.

Multiplication result is by definition `(a + i * b) * (c + i * d) = (a * c - b * d) + (b * c + a * d) * i`.

The reciprocal of a non-zero complex number is `1 / (a + i * b) = a/(a^2 + b^2) - b/(a^2 + b^2) * i`.

Dividing a complex number `a + i * b` by another `c + i * d` gives: `(a + i * b) / (c + i * d) = (a * c + b * d)/(c^2 + d^2) + (b * c - a * d)/(c^2 + d^2) * i`.

Exponent of a complex number can be expressed as `exp(a + i * b) = exp(a) * exp(i * b)`, and the last term is given by Euler's formula `exp(i * b) = cos(b) + i * sin(b)`.

Implement the following operations:

• addition, subtraction, multiplication and division of two complex numbers,
• conjugate, absolute value, exponent of a given complex number.

Assume the programming language you are using does not have an implementation of complex numbers.

For installation and learning resources, refer to the exercism help page.

For running the tests provided, you will need the Minitest gem. Open a terminal window and run the following command to install minitest:

``````gem install minitest
``````

If you would like color output, you can `require 'minitest/pride'` in the test file, or note the alternative instruction, below, for running the test file.

Run the tests from the exercise directory using the following command:

``````ruby complex_numbers_test.rb
``````

To include color from the command line:

``````ruby -r minitest/pride complex_numbers_test.rb
``````

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

### complex_numbers_test.rb

``````require 'minitest/autorun'
require_relative 'complex_numbers'

# Common test data version: 1.0.0 '117d062'
class ComplexNumberTest < Minitest::Test
def test_imaginary_unit
# skip
expected = ComplexNumber.new(-1, 0)
assert_equal expected, ComplexNumber.new(0, 1) * ComplexNumber.new(0, 1)
end

skip
expected = ComplexNumber.new(3, 0)
assert_equal expected, ComplexNumber.new(1, 0) + ComplexNumber.new(2, 0)
end

skip
expected = ComplexNumber.new(0, 3)
assert_equal expected, ComplexNumber.new(0, 1) + ComplexNumber.new(0, 2)
end

skip
expected = ComplexNumber.new(4, 6)
assert_equal expected, ComplexNumber.new(1, 2) + ComplexNumber.new(3, 4)
end

def test_subtract_purely_real_numbers
skip
expected = ComplexNumber.new(-1, 0)
assert_equal expected, ComplexNumber.new(1, 0) - ComplexNumber.new(2, 0)
end

def test_subtract_purely_imaginary_numbers
skip
expected = ComplexNumber.new(0, -1)
assert_equal expected, ComplexNumber.new(0, 1) - ComplexNumber.new(0, 2)
end

def test_subtract_numbers_with_real_and_imaginary_part
skip
expected = ComplexNumber.new(-2, -2)
assert_equal expected, ComplexNumber.new(1, 2) - ComplexNumber.new(3, 4)
end

def test_multiply_purely_real_numbers
skip
expected = ComplexNumber.new(2, 0)
assert_equal expected, ComplexNumber.new(1, 0) * ComplexNumber.new(2, 0)
end

def test_multiply_purely_imaginary_numbers
skip
expected = ComplexNumber.new(-2, 0)
assert_equal expected, ComplexNumber.new(0, 1) * ComplexNumber.new(0, 2)
end

def test_multiply_numbers_with_real_and_imaginary_part
skip
expected = ComplexNumber.new(-5, 10)
assert_equal expected, ComplexNumber.new(1, 2) * ComplexNumber.new(3, 4)
end

def test_divide_purely_real_numbers
skip
expected = ComplexNumber.new(0.5, 0)
assert_equal expected, ComplexNumber.new(1, 0) / ComplexNumber.new(2, 0)
end

def test_divide_purely_imaginary_numbers
skip
expected = ComplexNumber.new(0.5, 0)
assert_equal expected, ComplexNumber.new(0, 1) / ComplexNumber.new(0, 2)
end

def test_divide_numbers_with_real_and_imaginary_part
skip
expected = ComplexNumber.new(0.44, 0.08)
assert_equal expected, ComplexNumber.new(1, 2) / ComplexNumber.new(3, 4)
end

def test_absolute_value_of_a_positive_purely_real_number
skip
expected = 5
assert_equal expected, ComplexNumber.new(5, 0).abs
end

def test_absolute_value_of_a_negative_purely_real_number
skip
expected = 5
assert_equal expected, ComplexNumber.new(-5, 0).abs
end

def test_absolute_value_of_a_purely_imaginary_number_with_positive_imaginary_part
skip
expected = 5
assert_equal expected, ComplexNumber.new(0, 5).abs
end

def test_absolute_value_of_a_purely_imaginary_number_with_negative_imaginary_part
skip
expected = 5
assert_equal expected, ComplexNumber.new(0, -5).abs
end

def test_absolute_value_of_a_number_with_real_and_imaginary_part
skip
expected = 5
assert_equal expected, ComplexNumber.new(3, 4).abs
end

def test_conjugate_a_purely_real_number
skip
expected = ComplexNumber.new(5, 0)
assert_equal expected, ComplexNumber.new(5, 0).conjugate
end

def test_conjugate_a_purely_imaginary_number
skip
expected = ComplexNumber.new(0, -5)
assert_equal expected, ComplexNumber.new(0, 5).conjugate
end

def test_conjugate_a_number_with_real_and_imaginary_part
skip
expected = ComplexNumber.new(1, -1)
assert_equal expected, ComplexNumber.new(1, 1).conjugate
end

def test_real_part_of_a_purely_real_number
skip
expected = 1
assert_equal expected, ComplexNumber.new(1, 0).real
end

def test_real_part_of_a_purely_imaginary_number
skip
expected = 0
assert_equal expected, ComplexNumber.new(0, 1).real
end

def test_real_part_of_a_number_with_real_and_imaginary_part
skip
expected = 1
assert_equal expected, ComplexNumber.new(1, 2).real
end

def test_imaginary_part_of_a_purely_real_number
skip
expected = 0
assert_equal expected, ComplexNumber.new(1, 0).imaginary
end

def test_imaginary_part_of_a_purely_imaginary_number
skip
expected = 1
assert_equal expected, ComplexNumber.new(0, 1).imaginary
end

def test_imaginary_part_of_a_number_with_real_and_imaginary_part
skip
expected = 2
assert_equal expected, ComplexNumber.new(1, 2).imaginary
end

def test_eulers_identityformula
skip
expected = ComplexNumber.new(-1, 0)
assert_equal expected, ComplexNumber.new(0, Math::PI).exp
end

def test_exponential_of_0
skip
expected = ComplexNumber.new(1, 0)
assert_equal expected, ComplexNumber.new(0, 0).exp
end

def test_exponential_of_a_purely_real_number
skip
expected = ComplexNumber.new(Math::E, 0)
assert_equal expected, ComplexNumber.new(1, 0).exp
end

# Problems in exercism evolve over time, as we find better ways to ask
# questions.
# The version number refers to the version of the problem you solved,
#
# Define a constant named VERSION inside of the top level BookKeeping
# module, which may be placed near the end of your file.
#
# In your file, it will look like this:
#
# module BookKeeping
#   VERSION = 1 # Where the version number matches the one in the test.
# end
#
# http://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/constants.html

def test_bookkeeping
skip
assert_equal 1, BookKeeping::VERSION
end
end``````
``````# ComplexNumber
#
# An immutable number type representing complex numbers.
class ComplexNumber

# Initializes a new complex number with the given real and imaginary parts.
# @param real [Integer, Real]
# @param imaginary [Integer, Real]
def initialize(real, imaginary = 0)
@real = real
@imaginary = imaginary
end

# Returns a new ComplexNumber that is the sum of self and the other
# complex number.
# @param other [ComplexNumber]
# @return [ComplexNumber]
def +(other)
self.class.new(@real + other.real, @imaginary + other.imaginary)
end

# Returns a new ComplexNumber that is the difference of self and the other
# complex number.
# @param other [ComplexNumber]
# @return [ComplexNumber]
def -(other)
self.class.new(@real - other.real, @imaginary - other.imaginary)
end

# Returns a new ComplexNumber that is the product of self and the other
# complex number.
# @param other [ComplexNumber]
# @return [ComplexNumber]
def *(other)
self.class.new(@real * other.real - @imaginary * other.imaginary,
@imaginary * other.real + @real * other.imaginary)
end

# Returns a new ComplexNumber that is the product of self and the other
# complex number.
# @param other [ComplexNumber]
# @return [ComplexNumber]
def /(other)
q = (other.real**2 + other.imaginary**2).to_f
r = @real * other.real + @imaginary * other.imaginary
i = @imaginary * other.real - @real * other.imaginary

self.class.new(r / q, i / q)
end

# Is this number equal to other?
# @return [Boolean]
def ==(other)
return false unless other.is_a? ComplexNumber
(self - other).abs < 1e-12
end

# Returns the absolute value.
# @return [Float]
def abs
Math.sqrt(@real**2 + @imaginary**2)
end

# Returns the square of the absolute value.
# @return [Float]
def abs2
@real**2 + @imaginary**2
end

# Returns the complex conjugate.
# @return [ComplexNumber]
def conjugate
self.class.new(@real, -@imaginary)
end

# Returns the e**self.
# @return [ComplexNumber]
def exp
self.class.new(Math.exp(@real)) *
self.class.new(Math.cos(@imaginary), Math.sin(@imaginary))
end

# Is this a real number?
# @return [Boolean]
def real?
@imaginary.zero?
end

# Converts self to an Integer.
# @raise [RangeError] if it has a non-zero imaginary part.
# @return [Integer]
def to_i
fail RangeError, "Can't convert #{self} to an Integer." unless real?
@real.to_i
end

# Converts self to a Float.
# @raise [RangeError] if it has a non-zero imaginary part.
# @return [Float]
def to_f
fail RangeError, "Can't convert #{self} to a Float." unless real?
@real.to_f
end

# Converts self to a Rational.
# @raise [RangeError] if it has a non-zero imaginary part.
# @return [Rational]
def to_r
fail RangeError, "Can't convert #{self} to a Rational." unless real?
@real.to_r
end

# Returns a string representation.
# @return [String]
def to_s
"(#{@real} + #{@imaginary}i)"
end
alias inspect to_s
end

# BookKeeping for exercism test versions.
module BookKeeping
VERSION = 1 # Test version
end``````