defmodule ComplexNumbers do @typedoc """ In this module, complex numbers are represented as a tuple-pair containing the real and imaginary parts. For example, the real number `1` is `{1, 0}`, the imaginary number `i` is `{0, 1}` and the complex number `4+3i` is `{4, 3}'. """ @type complex :: {number, number} @doc """ Return the real part of a complex number """ @spec real(a :: complex) :: number def real({r, _i}), do: r @doc """ Return the imaginary part of a complex number """ @spec imaginary(a :: complex) :: number def imaginary({_r, i}), do: i @doc """ Multiply two complex numbers, or a real and a complex number """ @spec mul(a :: complex | number, b :: complex | number) :: complex def mul(n, {r, i}) when is_number(n), do: mul({r, i}, to_complex(n)) def mul({r, i}, n) when is_number(n), do: mul(to_complex(n), {r, i}) def mul({ar, ai}, {br, bi}), do: {ar * br - ai * bi, ar * bi + ai * br} @doc """ Add two complex numbers, or a real and a complex number """ @spec add(a :: complex | number, b :: complex | number) :: complex def add(n, {r, i}) when is_number(n), do: add({r, i}, to_complex(n)) def add({r, i}, n) when is_number(n), do: add(to_complex(n), {r, i}) def add({ar, ai}, {br, bi}), do: {ar + br, ai + bi} @doc """ Subtract two complex numbers, or a real and a complex number """ @spec sub(a :: complex | number, b :: complex | number) :: complex def sub(n, {r, i}) when is_number(n), do: sub(to_complex(n), {r, i}) def sub({r, i}, n) when is_number(n), do: sub({r, i}, to_complex(n)) def sub({ar, ai}, {br, bi}), do: {ar - br, ai - bi} @doc """ Divide two complex numbers, or a real and a complex number """ @spec div(a :: complex | number, b :: complex | number) :: complex def div(n, {r, i}) when is_number(n), do: __MODULE__.div(to_complex(n), {r, i}) def div({r, i}, n) when is_number(n), do: __MODULE__.div({r, i}, to_complex(n)) def div({ar, ai}, {br, bi}), do: {(ar * br + ai * bi)/(br ** 2 + bi ** 2), (ai * br - ar * bi)/(br ** 2 + bi ** 2)} @doc """ Absolute value of a complex number """ @spec abs(a :: complex) :: number def abs({r, i}), do: (r ** 2 + i ** 2) ** 0.5 @doc """ Conjugate of a complex number """ @spec conjugate(a :: complex) :: complex def conjugate({r, i}), do: {r, -i} @doc """ Exponential of a complex number """ @spec exp(a :: complex) :: complex def exp({r, i}), do: mul({:math.exp(r), 0}, {:math.cos(i), :math.sin(i)}) defp to_complex(n) when is_number(n), do: {n, 0} end