exercism/elixir/complex-numbers/lib/complex_numbers.ex

74 lines
2.5 KiB
Elixir

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