-module(ratioed). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([from_i/1, to_i/1, to_f/1, to_string/1, compare/2, from_i2/2, add/2, sub/2, mul/2, 'div'/2, from_f_epsilon/2, from_f/1]). -export_type([ratio/0]). -opaque ratio() :: {ratio, integer(), integer()}. -file("/home/julian/projects/ratioed/src/ratioed.gleam", 14). -spec from_i(integer()) -> ratio(). from_i(N) -> {ratio, N, 1}. -file("/home/julian/projects/ratioed/src/ratioed.gleam", 38). -spec to_i(ratio()) -> integer(). to_i(A) -> case erlang:element(3, A) of 0 -> 0; Gleam@denominator -> erlang:element(2, A) div Gleam@denominator end. -file("/home/julian/projects/ratioed/src/ratioed.gleam", 43). -spec to_f(ratio()) -> float(). to_f(Ratio) -> case gleam@int:to_float(erlang:element(3, Ratio)) of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator -> gleam@int:to_float(erlang:element(2, Ratio)) / Gleam@denominator end. -file("/home/julian/projects/ratioed/src/ratioed.gleam", 48). -spec to_string(ratio()) -> binary(). to_string(Ratio) -> <<<<(gleam@int:to_string(erlang:element(2, Ratio)))/binary, "/"/utf8>>/binary, (gleam@int:to_string(erlang:element(3, Ratio)))/binary>>. -file("/home/julian/projects/ratioed/src/ratioed.gleam", 53). -spec compare(ratio(), ratio()) -> gleam@order:order(). compare(A, B) -> gleam@int:compare( erlang:element(2, A) * erlang:element(3, B), erlang:element(3, A) * erlang:element(2, B) ). -file("/home/julian/projects/ratioed/src/ratioed.gleam", 82). -spec abs(integer()) -> integer(). abs(X) -> case X < 0 of true -> - X; false -> X end. -file("/home/julian/projects/ratioed/src/ratioed.gleam", 93). -spec do_gcd(integer(), integer()) -> integer(). do_gcd(X, Y) -> case X =:= 0 of true -> Y; false -> _assert_subject = gleam@int:modulo(Y, X), {ok, Z} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail, module => <<"ratioed"/utf8>>, function => <<"do_gcd"/utf8>>, line => 97}) end, do_gcd(Z, X) end. -file("/home/julian/projects/ratioed/src/ratioed.gleam", 89). -spec gcd(integer(), integer()) -> integer(). gcd(X, Y) -> do_gcd(abs(X), abs(Y)). -file("/home/julian/projects/ratioed/src/ratioed.gleam", 77). -spec simplify(integer(), integer()) -> ratio(). simplify(N, D) -> Gcd = gcd(N, D), {ratio, case Gcd of 0 -> 0; Gleam@denominator -> N div Gleam@denominator end, case Gcd of 0 -> 0; Gleam@denominator@1 -> D div Gleam@denominator@1 end}. -file("/home/julian/projects/ratioed/src/ratioed.gleam", 19). -spec from_i2(integer(), integer()) -> ratio(). from_i2(N, D) -> case {N, D} of {_, 0} -> {ratio, 0, 1}; {0, _} -> {ratio, 0, 1}; {_, _} when D < 0 -> simplify(- N, - D); {_, _} -> simplify(N, D) end. -file("/home/julian/projects/ratioed/src/ratioed.gleam", 58). -spec add(ratio(), ratio()) -> ratio(). add(A, B) -> from_i2( (erlang:element(2, A) * erlang:element(3, B)) + (erlang:element(3, A) * erlang:element( 2, B )), erlang:element(3, A) * erlang:element(3, B) ). -file("/home/julian/projects/ratioed/src/ratioed.gleam", 63). -spec sub(ratio(), ratio()) -> ratio(). sub(A, B) -> from_i2( (erlang:element(2, A) * erlang:element(3, B)) - (erlang:element(3, A) * erlang:element( 2, B )), erlang:element(3, A) * erlang:element(3, B) ). -file("/home/julian/projects/ratioed/src/ratioed.gleam", 68). -spec mul(ratio(), ratio()) -> ratio(). mul(A, B) -> from_i2( erlang:element(2, A) * erlang:element(2, B), erlang:element(3, A) * erlang:element(3, B) ). -file("/home/julian/projects/ratioed/src/ratioed.gleam", 73). -spec 'div'(ratio(), ratio()) -> ratio(). 'div'(A, B) -> from_i2( erlang:element(2, A) * erlang:element(3, B), erlang:element(3, A) * erlang:element(2, B) ). -file("/home/julian/projects/ratioed/src/ratioed.gleam", 109). -spec continued_fraction( any(), integer(), integer(), integer(), integer(), float(), float(), float(), float(), float(), float(), float() ) -> ratio(). continued_fraction(Tol, P, Q, Pp, Qq, X, Y, R, A, Nt, T, Tt) -> case R > Nt of true -> Np = (gleam@float:truncate(A) * P) + Pp, Nq = (gleam@float:truncate(A) * Q) + Qq, Pp@1 = P, P@1 = Np, Qq@1 = Q, Q@1 = Nq, X@1 = Y, Y@1 = R, R@1 = math:fmod(X@1, Y@1), A@1 = gleam@float:floor(case Y@1 of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator -> X@1 / Gleam@denominator end), Tt@1 = T, T@1 = Nt, Nt@1 = (A@1 * T@1) + Tt@1, continued_fraction( Tol, P@1, Q@1, Pp@1, Qq@1, X@1, Y@1, R@1, A@1, Nt@1, T@1, Tt@1 ); false -> I = gleam@float:truncate(gleam@float:ceiling(case (Y + T) of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator@1 -> (X - Tt) / Gleam@denominator@1 end)), from_i2((I * P) + Pp, (I * Q) + Qq) end. -file("/home/julian/projects/ratioed/src/ratioed.gleam", 103). -spec approx_ratio(float(), float()) -> ratio(). approx_ratio(Tol, X) -> A = gleam@float:floor(X), R = X - A, continued_fraction(Tol, 1, 0, 0, 1, X, 1.0, R, A, Tol, +0.0, Tol). -file("/home/julian/projects/ratioed/src/ratioed.gleam", 33). -spec from_f_epsilon(float(), float()) -> ratio(). from_f_epsilon(F, E) -> approx_ratio(E, F). -file("/home/julian/projects/ratioed/src/ratioed.gleam", 28). -spec from_f(float()) -> ratio(). from_f(F) -> approx_ratio(4.440892098500626e-16, F).