defmodule Wizard.Math do @moduledoc """ Wizard's Mathemagic functions """ @doc """ Pi (lel) """ def pi do 3.141592653589793 end @doc """ Euler's number (lel) """ def e do 2.718281828459045 end @doc """ sum(list) - produces the sum of all the elements in a list """ @spec sum(list) :: number def sum(list) do Enum.reduce(list, 0, fn(x, acc) -> x + acc end) end @doc """ Produces the greatest common divsor (GCD) of a and b TODO: fix negative arguments """ @spec gcd(integer, integer) :: integer def gcd(a,b) do cond do b == 0 -> a a > b -> gcd(b, rem(a,b)) a <= b -> gcd(a, rem(b,a)) end end @doc """ factorial(n) - produces n! """ @spec factorial(non_neg_integer) :: non_neg_integer def factorial(n) do cond do n < 0 -> raise ArithmeticError, message: "Argument must be a positive intger." n == 0 -> 1 n > 0 -> n * factorial(n-1) end end # """ # sqrt_rough(n) - produces a rough estimate of sqrt(n) # https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Rough_estimation # """ @spec sqrt_rough(number, number, non_neg_integer) :: number defp sqrt_rough(n, prev, acc) do cond do n <=0 -> cond do prev < 10 -> 2 * pow(10, acc-1) true -> 6 * pow(10, acc-1) end n > 0 -> sqrt_rough(div(n,100), n, 1+acc) end end # """ # sqrt(n) - produces the square root of n # """ @spec sqrt(number, number, number) :: number defp sqrt(s, n, x) do cond do x == ((1/n)*((n-1)*x + (s/pow(x,n-1)))) -> x true -> sqrt(s, n, ((1/n)*((n-1)*x + (s/pow(x,n-1))))) end end @doc """ sqrt(n) - produces the square root of n - wraps the sqrt(s,n,x) function for cleaner use """ @spec sqrt(number) :: number def sqrt(n) do cond do n < 0 -> raise ArithmeticError, message: "Arugment must be a positive number" n == 0 -> 0 n > 0 -> sqrt(n, 2, sqrt_rough(n,n,0)) end end @doc """ nth_root(a, n) - produces the nth root of a """ @spec nth_root(number, non_neg_integer) :: number def nth_root(a, n) do cond do n < 0 -> raise ArithmeticError, message: "Arugment n must be a positive number" n == 0 -> 0 n > 0 -> sqrt(a, n, sqrt_rough(n,n,0)) end end @doc """ pow(x, y) - produces x to the yth power TODO: fix decimal to fraction conversion the current version creates massive runtimes """ @spec pow(number, integer) :: number def pow(x,y) do # lol :math.pow(x,y) # cond do # y < 0 -> # 1/(x * pow(x, -1*y)) # y == 0 -> # 1 # # y > 0 && y < 1 -> # # numerator = to_string(y) |> String.split(".") |> List.last() |> String.to_integer # # denominator = to_string(y) |> String.split(".") |> List.last() |> String.length # # denominator = pow(10, denominator) # # IO.puts numerator # # IO.puts denominator # # nth_root(pow(x, numerator),denominator) # y == 1 -> # x # y > 0 -> # x * pow(x, y-1) # end end @doc """ log(b, n) - produces log_b n with default base of e """ @spec log(number, number) :: number def log(b \\ e,n) do :math.log(n)/:math.log(b) end @doc """ permutation(n, k) - produces k-permutations of n """ @spec permutation(non_neg_integer, non_neg_integer) :: non_neg_integer def permutation(n,k) do div(factorial(n), factorial(n-k)) end @doc """ combination(n, k) - produces n choose k """ @spec combination(non_neg_integer, non_neg_integer) :: non_neg_integer def combination(n,k) do div(factorial(n), (factorial(k)*factorial(n-k))) end end