Avatar of jongleur1983

jongleur1983's solution

to Complex Numbers in the C# Track

Published at Sep 19 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.

Running the tests

To run the tests, run the command dotnet test from within the exercise directory.

Initially, only the first test will be enabled. This is to encourage you to solve the exercise one step at a time. Once you get the first test passing, remove the Skip property from the next test and work on getting that test passing. Once none of the tests are skipped and they are all passing, you can submit your solution using exercism submit ComplexNumbers.cs

Further information

For more detailed information about the C# track, including how to get help if you're having trouble, please visit the exercism.io C# language page.

Source

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

ComplexNumbersTest.cs

// This file was auto-generated based on version 1.3.0 of the canonical data.

using System;
using Xunit;

public class ComplexNumbersTest
{
    [Fact]
    public void Real_part_of_a_purely_real_number()
    {
        var sut = new ComplexNumber(1, 0);
        Assert.Equal(1, sut.Real());
    }

    [Fact(Skip = "Remove to run test")]
    public void Real_part_of_a_purely_imaginary_number()
    {
        var sut = new ComplexNumber(0, 1);
        Assert.Equal(0, sut.Real());
    }

    [Fact(Skip = "Remove to run test")]
    public void Real_part_of_a_number_with_real_and_imaginary_part()
    {
        var sut = new ComplexNumber(1, 2);
        Assert.Equal(1, sut.Real());
    }

    [Fact(Skip = "Remove to run test")]
    public void Imaginary_part_of_a_purely_real_number()
    {
        var sut = new ComplexNumber(1, 0);
        Assert.Equal(0, sut.Imaginary());
    }

    [Fact(Skip = "Remove to run test")]
    public void Imaginary_part_of_a_purely_imaginary_number()
    {
        var sut = new ComplexNumber(0, 1);
        Assert.Equal(1, sut.Imaginary());
    }

    [Fact(Skip = "Remove to run test")]
    public void Imaginary_part_of_a_number_with_real_and_imaginary_part()
    {
        var sut = new ComplexNumber(1, 2);
        Assert.Equal(2, sut.Imaginary());
    }

    [Fact(Skip = "Remove to run test")]
    public void Imaginary_unit()
    {
        var sut = new ComplexNumber(0, 1);
        var expected = new ComplexNumber(-1, 0);
        Assert.Equal(expected.Real(), sut.Mul(new ComplexNumber(0, 1)).Real(), precision: 7);
        Assert.Equal(expected.Imaginary(), sut.Mul(new ComplexNumber(0, 1)).Imaginary(), precision: 7);
    }

    [Fact(Skip = "Remove to run test")]
    public void Add_purely_real_numbers()
    {
        var sut = new ComplexNumber(1, 0);
        var expected = new ComplexNumber(3, 0);
        Assert.Equal(expected.Real(), sut.Add(new ComplexNumber(2, 0)).Real(), precision: 7);
        Assert.Equal(expected.Imaginary(), sut.Add(new ComplexNumber(2, 0)).Imaginary(), precision: 7);
    }

    [Fact(Skip = "Remove to run test")]
    public void Add_purely_imaginary_numbers()
    {
        var sut = new ComplexNumber(0, 1);
        var expected = new ComplexNumber(0, 3);
        Assert.Equal(expected.Real(), sut.Add(new ComplexNumber(0, 2)).Real(), precision: 7);
        Assert.Equal(expected.Imaginary(), sut.Add(new ComplexNumber(0, 2)).Imaginary(), precision: 7);
    }

    [Fact(Skip = "Remove to run test")]
    public void Add_numbers_with_real_and_imaginary_part()
    {
        var sut = new ComplexNumber(1, 2);
        var expected = new ComplexNumber(4, 6);
        Assert.Equal(expected.Real(), sut.Add(new ComplexNumber(3, 4)).Real(), precision: 7);
        Assert.Equal(expected.Imaginary(), sut.Add(new ComplexNumber(3, 4)).Imaginary(), precision: 7);
    }

    [Fact(Skip = "Remove to run test")]
    public void Subtract_purely_real_numbers()
    {
        var sut = new ComplexNumber(1, 0);
        var expected = new ComplexNumber(-1, 0);
        Assert.Equal(expected.Real(), sut.Sub(new ComplexNumber(2, 0)).Real(), precision: 7);
        Assert.Equal(expected.Imaginary(), sut.Sub(new ComplexNumber(2, 0)).Imaginary(), precision: 7);
    }

    [Fact(Skip = "Remove to run test")]
    public void Subtract_purely_imaginary_numbers()
    {
        var sut = new ComplexNumber(0, 1);
        var expected = new ComplexNumber(0, -1);
        Assert.Equal(expected.Real(), sut.Sub(new ComplexNumber(0, 2)).Real(), precision: 7);
        Assert.Equal(expected.Imaginary(), sut.Sub(new ComplexNumber(0, 2)).Imaginary(), precision: 7);
    }

    [Fact(Skip = "Remove to run test")]
    public void Subtract_numbers_with_real_and_imaginary_part()
    {
        var sut = new ComplexNumber(1, 2);
        var expected = new ComplexNumber(-2, -2);
        Assert.Equal(expected.Real(), sut.Sub(new ComplexNumber(3, 4)).Real(), precision: 7);
        Assert.Equal(expected.Imaginary(), sut.Sub(new ComplexNumber(3, 4)).Imaginary(), precision: 7);
    }

    [Fact(Skip = "Remove to run test")]
    public void Multiply_purely_real_numbers()
    {
        var sut = new ComplexNumber(1, 0);
        var expected = new ComplexNumber(2, 0);
        Assert.Equal(expected.Real(), sut.Mul(new ComplexNumber(2, 0)).Real(), precision: 7);
        Assert.Equal(expected.Imaginary(), sut.Mul(new ComplexNumber(2, 0)).Imaginary(), precision: 7);
    }

    [Fact(Skip = "Remove to run test")]
    public void Multiply_purely_imaginary_numbers()
    {
        var sut = new ComplexNumber(0, 1);
        var expected = new ComplexNumber(-2, 0);
        Assert.Equal(expected.Real(), sut.Mul(new ComplexNumber(0, 2)).Real(), precision: 7);
        Assert.Equal(expected.Imaginary(), sut.Mul(new ComplexNumber(0, 2)).Imaginary(), precision: 7);
    }

    [Fact(Skip = "Remove to run test")]
    public void Multiply_numbers_with_real_and_imaginary_part()
    {
        var sut = new ComplexNumber(1, 2);
        var expected = new ComplexNumber(-5, 10);
        Assert.Equal(expected.Real(), sut.Mul(new ComplexNumber(3, 4)).Real(), precision: 7);
        Assert.Equal(expected.Imaginary(), sut.Mul(new ComplexNumber(3, 4)).Imaginary(), precision: 7);
    }

    [Fact(Skip = "Remove to run test")]
    public void Divide_purely_real_numbers()
    {
        var sut = new ComplexNumber(1, 0);
        var expected = new ComplexNumber(0.5, 0);
        Assert.Equal(expected.Real(), sut.Div(new ComplexNumber(2, 0)).Real(), precision: 7);
        Assert.Equal(expected.Imaginary(), sut.Div(new ComplexNumber(2, 0)).Imaginary(), precision: 7);
    }

    [Fact(Skip = "Remove to run test")]
    public void Divide_purely_imaginary_numbers()
    {
        var sut = new ComplexNumber(0, 1);
        var expected = new ComplexNumber(0.5, 0);
        Assert.Equal(expected.Real(), sut.Div(new ComplexNumber(0, 2)).Real(), precision: 7);
        Assert.Equal(expected.Imaginary(), sut.Div(new ComplexNumber(0, 2)).Imaginary(), precision: 7);
    }

    [Fact(Skip = "Remove to run test")]
    public void Divide_numbers_with_real_and_imaginary_part()
    {
        var sut = new ComplexNumber(1, 2);
        var expected = new ComplexNumber(0.44, 0.08);
        Assert.Equal(expected.Real(), sut.Div(new ComplexNumber(3, 4)).Real(), precision: 7);
        Assert.Equal(expected.Imaginary(), sut.Div(new ComplexNumber(3, 4)).Imaginary(), precision: 7);
    }

    [Fact(Skip = "Remove to run test")]
    public void Absolute_value_of_a_positive_purely_real_number()
    {
        var sut = new ComplexNumber(5, 0);
        Assert.Equal(5, sut.Abs());
    }

    [Fact(Skip = "Remove to run test")]
    public void Absolute_value_of_a_negative_purely_real_number()
    {
        var sut = new ComplexNumber(-5, 0);
        Assert.Equal(5, sut.Abs());
    }

    [Fact(Skip = "Remove to run test")]
    public void Absolute_value_of_a_purely_imaginary_number_with_positive_imaginary_part()
    {
        var sut = new ComplexNumber(0, 5);
        Assert.Equal(5, sut.Abs());
    }

    [Fact(Skip = "Remove to run test")]
    public void Absolute_value_of_a_purely_imaginary_number_with_negative_imaginary_part()
    {
        var sut = new ComplexNumber(0, -5);
        Assert.Equal(5, sut.Abs());
    }

    [Fact(Skip = "Remove to run test")]
    public void Absolute_value_of_a_number_with_real_and_imaginary_part()
    {
        var sut = new ComplexNumber(3, 4);
        Assert.Equal(5, sut.Abs());
    }

    [Fact(Skip = "Remove to run test")]
    public void Conjugate_a_purely_real_number()
    {
        var sut = new ComplexNumber(5, 0);
        var expected = new ComplexNumber(5, 0);
        Assert.Equal(expected.Real(), sut.Conjugate().Real(), precision: 7);
        Assert.Equal(expected.Imaginary(), sut.Conjugate().Imaginary(), precision: 7);
    }

    [Fact(Skip = "Remove to run test")]
    public void Conjugate_a_purely_imaginary_number()
    {
        var sut = new ComplexNumber(0, 5);
        var expected = new ComplexNumber(0, -5);
        Assert.Equal(expected.Real(), sut.Conjugate().Real(), precision: 7);
        Assert.Equal(expected.Imaginary(), sut.Conjugate().Imaginary(), precision: 7);
    }

    [Fact(Skip = "Remove to run test")]
    public void Conjugate_a_number_with_real_and_imaginary_part()
    {
        var sut = new ComplexNumber(1, 1);
        var expected = new ComplexNumber(1, -1);
        Assert.Equal(expected.Real(), sut.Conjugate().Real(), precision: 7);
        Assert.Equal(expected.Imaginary(), sut.Conjugate().Imaginary(), precision: 7);
    }

    [Fact(Skip = "Remove to run test")]
    public void Eulers_identity_formula()
    {
        var sut = new ComplexNumber(0, Math.PI);
        var expected = new ComplexNumber(-1, 0);
        Assert.Equal(expected.Real(), sut.Exp().Real(), precision: 7);
        Assert.Equal(expected.Imaginary(), sut.Exp().Imaginary(), precision: 7);
    }

    [Fact(Skip = "Remove to run test")]
    public void Exponential_of_0()
    {
        var sut = new ComplexNumber(0, 0);
        var expected = new ComplexNumber(1, 0);
        Assert.Equal(expected.Real(), sut.Exp().Real(), precision: 7);
        Assert.Equal(expected.Imaginary(), sut.Exp().Imaginary(), precision: 7);
    }

    [Fact(Skip = "Remove to run test")]
    public void Exponential_of_a_purely_real_number()
    {
        var sut = new ComplexNumber(1, 0);
        var expected = new ComplexNumber(Math.E, 0);
        Assert.Equal(expected.Real(), sut.Exp().Real(), precision: 7);
        Assert.Equal(expected.Imaginary(), sut.Exp().Imaginary(), precision: 7);
    }

    [Fact(Skip = "Remove to run test")]
    public void Exponential_of_a_number_with_real_and_imaginary_part()
    {
        var sut = new ComplexNumber(Math.Log(2.0), Math.PI);
        var expected = new ComplexNumber(-2, 0);
        Assert.Equal(expected.Real(), sut.Exp().Real(), precision: 7);
        Assert.Equal(expected.Imaginary(), sut.Exp().Imaginary(), precision: 7);
    }
}
using System;

public struct ComplexNumber
{
    private readonly double real;
    private readonly double imaginary;

    public ComplexNumber(double real, double imaginary)
    {
        this.real = real;
        this.imaginary = imaginary;
    }

    public double Real() => this.real;

    public double Imaginary() => this.imaginary;

    public ComplexNumber Mul(ComplexNumber other)
    {
        return new ComplexNumber(
            this.real * other.real - this.imaginary * other.imaginary,
            this.imaginary * other.real + this.real * other.imaginary);
    }

    public ComplexNumber Add(ComplexNumber other)
    {
        return new ComplexNumber(
            this.real + other.real, 
            this.imaginary + other.imaginary);
    }

    public ComplexNumber Sub(ComplexNumber other)
    {
        return new ComplexNumber(
            this.real - other.real,
            this.imaginary - other.imaginary);
    }

    public ComplexNumber Div(ComplexNumber other)
    {
        // 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.
        double divisor = other.real * other.real + other.imaginary * other.imaginary;
        return new ComplexNumber(
            real: (this.real * other.real + this.imaginary * other.imaginary) 
                / divisor,
            imaginary: (this.imaginary * other.real - this.real * other.imaginary)
                / divisor);
    }

    public double Abs()
    {
        return Math.Sqrt(this.real * this.real + this.imaginary * this.imaginary);
    }

    public ComplexNumber Conjugate()
    {
        return new ComplexNumber(this.real, -this.imaginary);
    }
    
    public ComplexNumber Exp()
    {
        return new ComplexNumber(Math.Exp(this.real),0)
            .Mul(
                new ComplexNumber(
                    Math.Cos(this.imaginary),
                    Math.Sin(this.imaginary)));
    }
}

Community comments

Find this solution interesting? Ask the author a question to learn more.

What can you learn from this solution?

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?