Packages

A fork of the math package. Experimental addition of arbitrary precision calculation of sqrt function as well as constants 𝛑, 𝛕, ℯ up to 1000 decimal places.

Current section

Files

Jump to
htam lib math arbitrary.ex
Raw

lib/math/arbitrary.ex

defmodule Math.AP do
@moduledoc """
Support for arbitrary precision calculation of some math functions and constants.
"""
@doc """
Returns π rounded to the number of decimal digits passed in.
Maximum number of decimal places is 1000. Default is 10 decimal places.
## Examples
iex> Math.AP.pi
#Decimal<3.1415926536>
iex> Math.AP.pi 30
#Decimal<3.141592653589793238462643383280>
"""
def pi(disp \\ 10) do
chudnovsky(disp)
end
defp chudnovsky(disp) when is_integer(disp) and (disp < 0 or disp > 1000) do
raise(
ArgumentError,
"Cannot display value to #{disp} decimal places; range 0 to 1000 inclusive."
)
end
defp chudnovsky(disp) when is_integer(disp) do
max_k = 80
prec = 1008
Decimal.set_context(%Decimal.Context{precision: prec})
values = {6, 1, 13_591_409, 1, 13_591_409}
sum = calculate_inter_val(1, max_k, values)
Decimal.mult(426_880, Decimal.sqrt(10005))
|> Decimal.div(sum)
|> Decimal.round(disp)
end
defp chudnovsky(_) do
raise(ArgumentError, "Unknown argument type. Enter an integer from 0 to 1000")
end
defp calculate_inter_val(counter, max_k, {_k, _m, _l, _x, s}) when counter == max_k do
s
end
defp calculate_inter_val(counter, max_k, {k, m, l, x, s}) do
val_cubed = &(&1 * &1 * &1)
m = ((val_cubed.(k) - 16 * k) * m) |> div(val_cubed.(counter))
l = l + 545_140_134
x = x * -262_537_412_640_768_000
s = Decimal.mult(m, l) |> Decimal.div(x) |> Decimal.add(s)
k = k + 12
calculate_inter_val(counter + 1, max_k, {k, m, l, x, s})
end
@doc """
Returns tau rounded to the number of decimal digits passed in.
Maximum number of decimal places is 1000. Default is 10 decimal places.
## Examples
iex> Math.AP.tau
#Decimal<6.2831853072>
"""
def tau(prec \\ 10) do
pi(prec) |> Decimal.mult(2)
end
@doc """
Finds the square root of a number to a particular precision.
## Examples
iex> Math.AP.sqrt(2, 10)
#Decimal<1.414213562>
iex> Math.AP.sqrt(2, 15)
#Decimal<1.41421356237310>
"""
def sqrt(num, prec) do
Decimal.set_context(%Decimal.Context{precision: prec})
Decimal.sqrt(num)
end
@doc """
Returns the mathematical constant ℯ rounded to the number of decimal digits passed in.
Maximum number of decimal places is 1000. Default is 10 decimal places.
## Examples
iex> Math.AP.e
"2.7182818285"
iex> Math.AP.e(30)
"2.718281828459045235360287471353"
"""
@iter 500
@prec 1000
def e(disp \\ 10) do
calculate_e(disp)
end
defp calculate_e(disp) when is_integer(disp) and (disp < 0 or disp > 1000) do
raise(
ArgumentError,
"Cannot display ℯ to #{disp} decimal places; range: 0 to 1000 inclusive."
)
end
defp calculate_e(disp) when is_integer(disp) do
Decimal.set_context(%Decimal.Context{precision: @prec})
{pre_sum, fact} = fact_div_fact_two()
(pre_sum + 2 * fact + @iter + 1)
|> Decimal.div(fact)
|> Decimal.round(disp)
end
defp calculate_e(_) do
raise(ArgumentError, "Unknown argument type. Enter an integer from 0 to 1000")
end
defp fact_div_fact_two(n \\ @iter, sum \\ 0, fact_to_2 \\ 1)
defp fact_div_fact_two(n, sum, fact_to_2) when n == 2 do
{sum, fact_to_2 * 2}
end
defp fact_div_fact_two(n, sum, fact_to_2) do
fact_to_2 = fact_to_2 * n
sum = sum + fact_to_2
fact_div_fact_two(n - 1, sum, fact_to_2)
end
end