Published at May 12 2019
·
0 comments

Instructions

Test suite

Solution

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`

.

Raising e to a complex exponent can be expressed as `e^(a + i * b) = e^a * e^(i * b)`

, the last term of which is given by Euler's formula `e^(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 Ruby resources 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
```

Wikipedia https://en.wikipedia.org/wiki/Complex_number

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

```
require 'minitest/autorun'
require_relative 'complex_numbers'
# Common test data version: 1.3.0 1e1c9ca
class ComplexNumbersTest < Minitest::Test
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_imaginary_unit
skip
expected = ComplexNumber.new(-1, 0)
assert_equal expected, ComplexNumber.new(0, 1) * ComplexNumber.new(0, 1)
end
def test_add_purely_real_numbers
skip
expected = ComplexNumber.new(3, 0)
assert_equal expected, ComplexNumber.new(1, 0) + ComplexNumber.new(2, 0)
end
def test_add_purely_imaginary_numbers
skip
expected = ComplexNumber.new(0, 3)
assert_equal expected, ComplexNumber.new(0, 1) + ComplexNumber.new(0, 2)
end
def test_add_numbers_with_real_and_imaginary_part
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_eulers_identity_formula
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
def test_exponential_of_a_number_with_real_and_imaginary_part
skip
expected = ComplexNumber.new(-2, 0)
assert_equal expected, ComplexNumber.new(Math.log(2), Math::PI).exp
end
end
```

```
class ComplexNumber
ADD_POWERS_OF_TWO = lambda do |complex_number|
complex_number.real**2 + complex_number.imaginary**2
end
private_constant :ADD_POWERS_OF_TWO
attr_reader :real, :imaginary
def initialize(real, imaginary)
@real = real
@imaginary = imaginary
end
def ==(other)
real == other.real && imaginary == other.imaginary
end
# (a + i * b) + (c + i * d) = (a + c) + (b + d) * i
def +(other)
self.class.new(
add_real(other),
add_imaginary(other)
)
end
# (a + i * b) - (c + i * d) = (a - c) + (b - d) * i
def -(other)
self.class.new(
subtract_real(other),
subtract_imaginary(other)
)
end
# (a + i * b) * (c + i * d) = (a * c - b * d) + (b * c + a * d) * i
def *(other)
self.class.new(
multiplication_real(other),
multiplication_imaginary(other)
)
end
# (a + i * b) / (c + i * d) =
# (a * c + b * d) / (c^2 + d^2) + (b * c - a * d) / (c^2 + d^2) * i
def /(other)
self.class.new(
divide_real(other),
divide_imaginary(other)
)
end
# |z| = sqrt(a^2 + b^2)
def abs
self
.then(&ADD_POWERS_OF_TWO)
.then(&Math.method(:sqrt))
end
# a - b * i
def conjugate
self.class.new(real, -imaginary)
end
# e^(a + i * b) = e^a * e^(i * b)
# => e^(i * b) = cos(b) + i * sin(b)
def exp
self.class.new(
Math.exp(real) * eulers_formula,
0
)
end
private
# (a + c)
def add_real(other)
real + other.real
end
# (b + d)
def add_imaginary(other)
imaginary + other.imaginary
end
# (a - c)
def subtract_real(other)
real - other.real
end
# (b - d)
def subtract_imaginary(other)
imaginary - other.imaginary
end
# (a * c - b * d)
def multiplication_real(other)
multiply_real(other) - multiply_imaginary(other)
end
# (b * c + a * d)
def multiplication_imaginary(other)
multiply_imaginary_to_real(other) + multiply_real_to_imaginary(other)
end
# (a * c)
def multiply_real(other)
real * other.real
end
# (a * d)
def multiply_real_to_imaginary(other)
real * other.imaginary
end
# (b * d)
def multiply_imaginary(other)
imaginary * other.imaginary
end
# (b * c)
def multiply_imaginary_to_real(other)
imaginary * other.real
end
# (a * c + b * d) / (c^2 + d^2)
def divide_real(other)
(multiply_real(other) + multiply_imaginary(other)) /
division_denominator(other)
end
# (b * c - a * d) / (c^2 + d^2)
def divide_imaginary(other)
(multiply_imaginary_to_real(other) - multiply_real_to_imaginary(other)) /
division_denominator(other)
end
# (c^2 + d^2)
def division_denominator(other)
other
.then(&ADD_POWERS_OF_TWO)
.to_f
end
# e^(i * b) = cos(b) + i * sin(b)
def eulers_formula
(Math.cos(imaginary) + Math.sin(imaginary)).round
end
end
```

A huge amount can be learned from reading other people’s code. This is why we wanted to give exercism users the option of making their solutions public.

Here are some questions to help you reflect on this solution and learn the most from it.

- What compromises have been made?
- Are there new concepts here that you could read more about to improve your understanding?

Level up your programming skills with 3,373 exercises across 50 languages, and insightful discussion with our volunteer team of welcoming mentors.
Exercism is
**100% free forever**.

## Community comments