-module(gcalc). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([pow/2, factorial/1, abs/1, sqrt/1, pow2/1, pow10/1, cbrt/1]). -export_type([math_error/0]). -type math_error() :: division_by_zero | value_out_of_range | unsupported_operation. -spec pow_iter(float(), float(), float()) -> float(). pow_iter(Base, Power, Accumulator) -> case Power of +0.0 -> Accumulator; _ -> pow_iter(Base, Power - 1.0, Base * Accumulator) end. -spec pow(float(), float()) -> float(). pow(Base, Power) -> pow_iter(Base, Power, 1.0). -spec factorial_iter(float(), float()) -> float(). factorial_iter(N, Accumulator) -> case N of +0.0 -> Accumulator; _ -> factorial_iter(N - 1.0, N * Accumulator) end. -spec factorial(float()) -> {ok, float()} | {error, math_error()}. factorial(N) -> case N < +0.0 of true -> {error, unsupported_operation}; false -> {ok, factorial_iter(N, 1.0)} end. -spec abs(float()) -> float(). abs(N) -> case N < +0.0 of true -> +0.0 - N; false -> N end. -spec sqrt_iter(float(), float(), float()) -> float(). sqrt_iter(X0, X1, N) -> case abs(X1 - X0) < 0.0001 of true -> X1; false -> X0@1 = X1, X1@1 = (X0@1 + (case X0@1 of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator -> N / Gleam@denominator end)) / 2.0, sqrt_iter(X0@1, X1@1, N) end. -spec sqrt(float()) -> {ok, float()} | {error, math_error()}. sqrt(N) -> case N < +0.0 of true -> {error, value_out_of_range}; false -> {ok, sqrt_iter(+0.0, 1.0, N)} end. -spec pow2_iter(float(), float()) -> float(). pow2_iter(N, Accumulator) -> case N of +0.0 -> Accumulator; _ -> pow2_iter(N - 1.0, 2.0 * Accumulator) end. -spec pow2(float()) -> {ok, float()} | {error, math_error()}. pow2(N) -> case N < +0.0 of true -> {error, value_out_of_range}; false -> {ok, pow2_iter(N, 1.0)} end. -spec pow10_iter(float(), float()) -> float(). pow10_iter(N, Accumulator) -> case N of +0.0 -> Accumulator; _ -> pow10_iter(N - 1.0, 10.0 * Accumulator) end. -spec pow10(float()) -> {ok, float()} | {error, math_error()}. pow10(N) -> case N < +0.0 of true -> {error, value_out_of_range}; false -> {ok, pow10_iter(N, 1.0)} end. -spec cbrt_iter(float(), float(), float()) -> float(). cbrt_iter(X0, X1, N) -> case abs(X1 - X0) < 0.0001 of true -> X1; false -> X0@1 = X1, X1@1 = (X0@1 + (case (X0@1 * X0@1) of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator -> N / Gleam@denominator end)) / 2.0, cbrt_iter(X0@1, X1@1, N) end. -spec cbrt(float()) -> {ok, float()} | {error, math_error()}. cbrt(N) -> case N < +0.0 of true -> {error, value_out_of_range}; false -> {ok, cbrt_iter(+0.0, 1.0, N)} end.