rational_numbers
This commit is contained in:
80
elixir/rational-numbers/lib/rational_numbers.ex
Normal file
80
elixir/rational-numbers/lib/rational_numbers.ex
Normal file
@@ -0,0 +1,80 @@
|
||||
defmodule RationalNumbers do
|
||||
@type rational :: {integer, integer}
|
||||
alias Kernel, as: K
|
||||
|
||||
@doc """
|
||||
Add two rational numbers
|
||||
"""
|
||||
@spec add(a :: rational, b :: rational) :: rational
|
||||
def add({an, ad}, {bn, bd}), do: {an * bd + bn * ad, ad * bd} |> reduce()
|
||||
|
||||
@doc """
|
||||
Subtract two rational numbers
|
||||
"""
|
||||
@spec subtract(a :: rational, b :: rational) :: rational
|
||||
def subtract({an, ad}, {bn, bd}), do: {an * bd - bn * ad, ad * bd} |> reduce()
|
||||
|
||||
@doc """
|
||||
Multiply two rational numbers
|
||||
"""
|
||||
@spec multiply(a :: rational, b :: rational) :: rational
|
||||
def multiply({an, ad}, {bn, bd}), do: {an * bn, ad * bd} |> reduce()
|
||||
|
||||
@doc """
|
||||
Divide two rational numbers
|
||||
"""
|
||||
@spec divide_by(num :: rational, den :: rational) :: rational
|
||||
def divide_by({an, ad}, {bn, bd}) when bn != 0, do: {an * bd, bn * ad} |> reduce()
|
||||
|
||||
@doc """
|
||||
Absolute value of a rational number
|
||||
"""
|
||||
@spec abs(a :: rational) :: rational
|
||||
def abs({an, ad}), do: {K.abs(an), K.abs(ad)} |> reduce()
|
||||
|
||||
@doc """
|
||||
Exponentiation of a rational number by an integer
|
||||
"""
|
||||
@spec pow_rational(a :: rational, n :: integer | float) :: rational
|
||||
def pow_rational({an, ad}, n) when is_integer(n) and n >= 0, do: {an ** n, ad ** n} |> reduce()
|
||||
|
||||
def pow_rational({an, ad}, n) when is_integer(n) and n < 0,
|
||||
do: {ad ** K.abs(n), an ** K.abs(n)} |> reduce()
|
||||
|
||||
def pow_rational({an, ad}, x) when is_float(x), do: ad ** x / an ** x
|
||||
|
||||
@doc """
|
||||
Exponentiation of a real number by a rational number
|
||||
"""
|
||||
@spec pow_real(x :: integer, n :: rational) :: float
|
||||
def pow_real(x, {_nn, nd} = n) when is_integer(x) and nd < 0, do: pow_real(x, normalize(n))
|
||||
def pow_real(x, {nn, nd}) when is_integer(x), do: x ** nn ** (1 / nd)
|
||||
|
||||
@doc """
|
||||
Reduce a rational number to its lowest terms
|
||||
"""
|
||||
@spec reduce(a :: rational) :: rational
|
||||
def reduce({an, ad} = a),
|
||||
do: a |> normalize() |> cut(Integer.gcd(an, ad))
|
||||
|
||||
# @doc """
|
||||
# Divides a nominator and denominator by integer
|
||||
# """
|
||||
@spec cut(a :: rational, n :: integer) :: rational
|
||||
defp cut({an, ad}, n), do: {K.div(an, n), K.div(ad, n)}
|
||||
|
||||
# @doc """
|
||||
# Turns signs of nominator and denominator when negative denominator
|
||||
# """
|
||||
@spec normalize(a :: rational) :: rational
|
||||
defp normalize({an, ad}) when ad < 0, do: {K.-(an), K.-(ad)}
|
||||
defp normalize({an, ad}), do: {an, ad}
|
||||
|
||||
# @doc """
|
||||
# Calculate a greatest common divisor of two integers
|
||||
# """
|
||||
# @spec gcd(i :: integer, j :: integer) :: integer
|
||||
# defp gcd(i, 0), do: K.abs(i)
|
||||
# defp gcd(0, j), do: K.abs(j)
|
||||
# defp gcd(i, j), do: gcd(j, K.rem(i, j))
|
||||
end
|
||||
Reference in New Issue
Block a user