Current section
Files
Jump to
Current section
Files
src/glib@fraction.erl
-module(glib@fraction).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([compare/2, equals/2, to_float/1, to_int/1, numerator/1, denominator/1, proper_numerator/1, proper_whole/1, to_string/1, to_proper_string/1, negate/1, abs/1, new/2, new2/3, inverse/1, reduce/1, multiply/2, divide/2, power/2, add/2, sub/2, from_float/1, from_string/1]).
-export_type([fraction/0, fraction_error/0, internal_fraction/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" General Fraction functions\n"
" Fraction type allow for accurate storage and manipulation\n"
" of fractions\n"
" \n"
" There is a current limitation of 9007199254740991 for the \n"
" numerator and denominator. This is because this is the largest\n"
" 'safe' integer in Javascript.\n"
).
-type fraction() :: {fraction, integer(), integer()}.
-type fraction_error() :: {zero_denominator, binary()} |
{overflow, binary()} |
{too_large, binary()} |
{conversion_error, binary()} |
{divide_by_zero, binary()}.
-type internal_fraction() :: {internal_fraction,
fraction(),
fraction(),
integer(),
float(),
float(),
float(),
float()}.
-file("src/glib/fraction.gleam", 202).
-spec compare(fraction(), fraction()) -> gleam@order:order().
compare(Fr1, Fr2) ->
gleam@bool:guard(
Fr1 =:= Fr2,
eq,
fun() ->
gleam@int:compare(
erlang:element(2, Fr1) * erlang:element(3, Fr2),
erlang:element(3, Fr1) * erlang:element(2, Fr2)
)
end
).
-file("src/glib/fraction.gleam", 207).
-spec equals(fraction(), fraction()) -> boolean().
equals(Fr1, Fr2) ->
compare(Fr1, Fr2) =:= eq.
-file("src/glib/fraction.gleam", 211).
-spec to_float(fraction()) -> float().
to_float(Fr1) ->
case erlang:float(erlang:element(3, Fr1)) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> erlang:float(erlang:element(2, Fr1)) / Gleam@denominator
end.
-file("src/glib/fraction.gleam", 215).
-spec to_int(fraction()) -> integer().
to_int(Fr1) ->
case erlang:element(3, Fr1) of
0 -> 0;
Gleam@denominator -> erlang:element(2, Fr1) div Gleam@denominator
end.
-file("src/glib/fraction.gleam", 219).
-spec numerator(fraction()) -> integer().
numerator(Fr1) ->
erlang:element(2, Fr1).
-file("src/glib/fraction.gleam", 223).
-spec denominator(fraction()) -> integer().
denominator(Fr1) ->
erlang:element(3, Fr1).
-file("src/glib/fraction.gleam", 227).
-spec proper_numerator(fraction()) -> integer().
proper_numerator(Fr1) ->
gleam@int:absolute_value(case erlang:element(3, Fr1) of
0 -> 0;
Gleam@denominator -> erlang:element(2, Fr1) rem Gleam@denominator
end).
-file("src/glib/fraction.gleam", 231).
-spec proper_whole(fraction()) -> integer().
proper_whole(Fr1) ->
to_int(Fr1).
-file("src/glib/fraction.gleam", 312).
-spec to_string(fraction()) -> binary().
to_string(Fr1) ->
<<<<(erlang:integer_to_binary(erlang:element(2, Fr1)))/binary, "/"/utf8>>/binary,
(erlang:integer_to_binary(erlang:element(3, Fr1)))/binary>>.
-file("src/glib/fraction.gleam", 316).
-spec to_proper_string(fraction()) -> binary().
to_proper_string(Fr1) ->
gleam@bool:guard(
erlang:element(2, Fr1) =:= 0,
<<"0"/utf8>>,
fun() ->
gleam@bool:guard(
erlang:element(2, Fr1) =:= erlang:element(3, Fr1),
<<"1"/utf8>>,
fun() ->
gleam@bool:guard(
erlang:element(2, Fr1) =:= - erlang:element(3, Fr1),
<<"-1"/utf8>>,
fun() ->
case - gleam@int:absolute_value(
erlang:element(2, Fr1)
)
< - erlang:element(3, Fr1) of
true ->
Prop_num = proper_numerator(Fr1),
case Prop_num =:= 0 of
true ->
erlang:integer_to_binary(
proper_whole(Fr1)
);
false ->
<<<<<<<<(erlang:integer_to_binary(
proper_whole(
Fr1
)
))/binary,
" "/utf8>>/binary,
(erlang:integer_to_binary(
Prop_num
))/binary>>/binary,
"/"/utf8>>/binary,
(erlang:integer_to_binary(
erlang:element(3, Fr1)
))/binary>>
end;
false ->
to_string(Fr1)
end
end
)
end
)
end
).
-file("src/glib/fraction.gleam", 609).
-spec divide_while_even(integer()) -> integer().
divide_while_even(T) ->
case gleam@int:is_even(T) of
true ->
divide_while_even(T div 2);
false ->
T
end.
-file("src/glib/fraction.gleam", 593).
-spec reduce_t(integer(), {integer(), integer()}) -> integer().
reduce_t(T, Uv) ->
{U, V} = Uv,
T@1 = divide_while_even(T),
{U@1, V@1} = case gleam@int:compare(T@1, 0) of
gt ->
{- T@1, V};
_ ->
{U, T@1}
end,
T@2 = (V@1 - U@1) div 2,
case T@2 =:= 0 of
true ->
U@1;
false ->
reduce_t(T@2, {U@1, V@1})
end.
-file("src/glib/fraction.gleam", 178).
-spec negate(fraction()) -> {ok, fraction()} | {error, fraction_error()}.
negate(Fr) ->
case - erlang:element(2, Fr) > 9007199254740991 of
true ->
{error,
{overflow,
<<"Cannot negate "/utf8,
(erlang:integer_to_binary(erlang:element(2, Fr)))/binary>>}};
false ->
{ok, {fraction, - erlang:element(2, Fr), erlang:element(3, Fr)}}
end.
-file("src/glib/fraction.gleam", 187).
-spec abs(fraction()) -> {ok, fraction()} | {error, fraction_error()}.
abs(Fr) ->
case erlang:element(2, Fr) >= 0 of
true ->
{ok, Fr};
false ->
negate(Fr)
end.
-file("src/glib/fraction.gleam", 426).
-spec mul_pos(integer(), integer()) -> {ok, integer()} |
{error, fraction_error()}.
mul_pos(X, Y) ->
M = X * Y,
case M > 9007199254740991 of
true ->
{error,
{overflow,
<<<<<<"multiplying "/utf8,
(erlang:integer_to_binary(X))/binary>>/binary,
" and "/utf8>>/binary,
(erlang:integer_to_binary(Y))/binary>>}};
false ->
{ok, M}
end.
-file("src/glib/fraction.gleam", 616).
-spec internal_calc(float(), internal_fraction()) -> internal_fraction().
internal_calc(Value, Fr) ->
A2 = erlang:trunc(case erlang:element(6, Fr) =:= +0.0 of
true ->
erlang:float(9007199254740991);
false ->
case erlang:element(6, Fr) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> erlang:element(5, Fr) / Gleam@denominator
end
end),
X2 = erlang:element(6, Fr),
Y2 = erlang:element(5, Fr) - (erlang:float(A2) * erlang:element(6, Fr)),
Fr2 = {fraction,
(erlang:element(4, Fr) * erlang:element(2, erlang:element(3, Fr))) + erlang:element(
2,
erlang:element(2, Fr)
),
(erlang:element(4, Fr) * erlang:element(3, erlang:element(3, Fr))) + erlang:element(
3,
erlang:element(2, Fr)
)},
Fraction = case erlang:float(erlang:element(3, Fr2)) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator@1 -> erlang:float(erlang:element(2, Fr2)) / Gleam@denominator@1
end,
Delta2 = gleam@float:absolute_value(Value - Fraction),
{internal_fraction,
erlang:element(3, Fr),
Fr2,
A2,
X2,
Y2,
erlang:element(8, Fr),
Delta2}.
-file("src/glib/fraction.gleam", 71).
-spec new(integer(), integer()) -> {ok, fraction()} | {error, fraction_error()}.
new(Numerator, Denominator) ->
gleam@bool:guard(
Denominator =:= 0,
{error, {zero_denominator, <<"Denominator is zero"/utf8>>}},
fun() -> case Denominator < 0 of
true ->
gleam@bool:guard(
(Numerator =:= -9007199254740991) orelse (Denominator
=:= -9007199254740991),
{error,
{overflow,
<<"Denominator or Numerator is -9007199254740991"/utf8>>}},
fun() ->
{ok, {fraction, - Numerator, - Denominator}}
end
);
false ->
{ok, {fraction, Numerator, Denominator}}
end end
).
-file("src/glib/fraction.gleam", 90).
-spec new2(integer(), integer(), integer()) -> {ok, fraction()} |
{error, fraction_error()}.
new2(Whole, Numerator, Denominator) ->
gleam@bool:guard(
Denominator =:= 0,
{error, {zero_denominator, <<"Denominator is zero"/utf8>>}},
fun() ->
gleam@bool:guard(
Denominator < 0,
{error,
{zero_denominator, <<"Denominator is less than zero"/utf8>>}},
fun() ->
gleam@bool:guard(
Numerator < 0,
{error,
{zero_denominator,
<<"Numerator is less than zero"/utf8>>}},
fun() ->
Numerator@1 = case Whole < 0 of
true ->
(Whole * Denominator) - Numerator;
false ->
(Whole * Denominator) + Numerator
end,
gleam@bool:guard(
(Numerator@1 < -9007199254740991) orelse (Numerator@1
> 9007199254740991),
{error,
{overflow, <<"Numerator overflows"/utf8>>}},
fun() ->
{ok, {fraction, Numerator@1, Denominator}}
end
)
end
)
end
)
end
).
-file("src/glib/fraction.gleam", 235).
-spec inverse(fraction()) -> {ok, fraction()} | {error, fraction_error()}.
inverse(Fr1) ->
gleam@bool:guard(
erlang:element(2, Fr1) =:= 0,
{error, {zero_denominator, <<"Inverse"/utf8>>}},
fun() ->
gleam@bool:guard(
erlang:element(2, Fr1) =:= -9007199254740991,
{error, {overflow, <<"Inverse"/utf8>>}},
fun() -> case erlang:element(2, Fr1) < 0 of
true ->
{ok,
{fraction,
- erlang:element(3, Fr1),
- erlang:element(2, Fr1)}};
false ->
{ok,
{fraction,
erlang:element(3, Fr1),
erlang:element(2, Fr1)}}
end end
)
end
).
-file("src/glib/fraction.gleam", 393).
-spec mul_check(integer(), integer()) -> {ok, integer()} |
{error, fraction_error()}.
mul_check(X, Y) ->
M = X * Y,
case (M < -9007199254740991) orelse (M > 9007199254740991) of
true ->
{error,
{overflow,
<<<<<<"multiplying "/utf8,
(erlang:integer_to_binary(X))/binary>>/binary,
" and "/utf8>>/binary,
(erlang:integer_to_binary(Y))/binary>>}};
false ->
{ok, M}
end.
-file("src/glib/fraction.gleam", 404).
-spec add_check(integer(), integer()) -> {ok, integer()} |
{error, fraction_error()}.
add_check(X, Y) ->
A = X + Y,
case (A < -9007199254740991) orelse (A > 9007199254740991) of
true ->
{error,
{overflow,
<<<<<<"adding "/utf8, (erlang:integer_to_binary(X))/binary>>/binary,
" and "/utf8>>/binary,
(erlang:integer_to_binary(Y))/binary>>}};
false ->
{ok, A}
end.
-file("src/glib/fraction.gleam", 415).
-spec sub_check(integer(), integer()) -> {ok, integer()} |
{error, fraction_error()}.
sub_check(X, Y) ->
S = X - Y,
case (S < -9007199254740991) orelse (S > 9007199254740991) of
true ->
{error,
{overflow,
<<<<<<"subtracting "/utf8,
(erlang:integer_to_binary(Y))/binary>>/binary,
" from "/utf8>>/binary,
(erlang:integer_to_binary(X))/binary>>}};
false ->
{ok, S}
end.
-file("src/glib/fraction.gleam", 437).
-spec parse_with_whole(binary(), binary()) -> {ok, fraction()} |
{error, fraction_error()}.
parse_with_whole(Whole, Fraction) ->
gleam@result:'try'(
begin
_pipe = gleam_stdlib:parse_int(Whole),
gleam@result:replace_error(_pipe, {conversion_error, Whole})
end,
fun(Whole@1) -> case gleam@string:split(Fraction, <<"/"/utf8>>) of
[Numer, Denom] ->
gleam@result:'try'(
begin
_pipe@1 = gleam_stdlib:parse_int(Numer),
gleam@result:replace_error(
_pipe@1,
{conversion_error, Numer}
)
end,
fun(Numer@1) ->
gleam@result:'try'(
begin
_pipe@2 = gleam_stdlib:parse_int(Denom),
gleam@result:replace_error(
_pipe@2,
{conversion_error, Denom}
)
end,
fun(Denom@1) ->
new2(Whole@1, Numer@1, Denom@1)
end
)
end
);
_ ->
{error, {conversion_error, Fraction}}
end end
).
-file("src/glib/fraction.gleam", 460).
-spec parse_fraction(binary()) -> {ok, fraction()} | {error, fraction_error()}.
parse_fraction(Fraction) ->
case gleam@string:split(Fraction, <<"/"/utf8>>) of
[Numer, Denom] ->
gleam@result:'try'(
begin
_pipe = gleam_stdlib:parse_int(Numer),
gleam@result:replace_error(_pipe, {conversion_error, Numer})
end,
fun(Numer@1) ->
gleam@result:'try'(
begin
_pipe@1 = gleam_stdlib:parse_int(Denom),
gleam@result:replace_error(
_pipe@1,
{conversion_error, Denom}
)
end,
fun(Denom@1) -> new(Numer@1, Denom@1) end
)
end
);
_ ->
{error, {conversion_error, Fraction}}
end.
-file("src/glib/fraction.gleam", 541).
-spec gcd(integer(), integer()) -> {ok, integer()} | {error, fraction_error()}.
gcd(U, V) ->
case (U =:= 0) orelse (V =:= 0) of
true ->
case (U =:= -9007199254740991) orelse (V =:= -9007199254740991) of
true ->
{error, {overflow, <<"gcd"/utf8>>}};
false ->
{ok,
gleam@int:absolute_value(U) + gleam@int:absolute_value(
V
)}
end;
false ->
case (gleam@int:absolute_value(U) =:= 1) orelse (gleam@int:absolute_value(
V
)
=:= 1) of
true ->
{ok, 1};
false ->
U@1 = case U > 0 of
true ->
- U;
false ->
U
end,
V@1 = case V > 0 of
true ->
- V;
false ->
V
end,
{U@3, V@3, K@1} = begin
_pipe = gleam@list:range(0, 31),
gleam@list:fold_until(
_pipe,
{U@1, V@1, 0},
fun(Vals, K) ->
{U@2, V@2, _} = Vals,
case K =:= 31 of
true ->
{stop, {-1, -1, -1}};
false ->
case gleam@int:is_odd(U@2) orelse gleam@int:is_odd(
V@2
) of
false ->
{continue,
{erlang:element(1, Vals) div 2,
erlang:element(2, Vals)
div 2,
K}};
true ->
{stop, {U@2, V@2, K}}
end
end
end
)
end,
gleam@bool:guard(
K@1 =:= -1,
{error, {overflow, <<"gcd iteration"/utf8>>}},
fun() ->
T = case gleam@int:is_odd(U@3) of
true ->
V@3;
false ->
- U@3 div 2
end,
U@4 = reduce_t(T, {U@3, V@3}),
{ok, - U@4 * erlang:'bsl'(1, K@1)}
end
)
end
end.
-file("src/glib/fraction.gleam", 152).
-spec reduce(fraction()) -> {ok, fraction()} | {error, fraction_error()}.
reduce(Fr) ->
gleam@bool:guard(
erlang:element(3, Fr) =:= 0,
{error, {zero_denominator, <<"Denominator is zero"/utf8>>}},
fun() ->
gleam@bool:guard(
erlang:element(2, Fr) =:= 0,
{ok, {fraction, 0, 1}},
fun() ->
Fr@1 = case {erlang:element(3, Fr) =:= -9007199254740991,
gleam@int:is_even(erlang:element(2, Fr))} of
{true, true} ->
{fraction,
erlang:element(2, Fr) div 2,
erlang:element(3, Fr) div 2};
{_, _} ->
Fr
end,
gleam@result:'try'(case erlang:element(3, Fr@1) < 0 of
true ->
case {erlang:element(2, Fr@1) =:= -9007199254740991,
erlang:element(3, Fr@1) =:= -9007199254740991} of
{false, false} ->
{ok,
{fraction,
- erlang:element(2, Fr@1),
- erlang:element(3, Fr@1)}};
{_, _} ->
{error,
{overflow,
<<"Denominator or Numerator is -9007199254740991"/utf8>>}}
end;
false ->
{ok, Fr@1}
end, fun(Fr@2) ->
gleam@result:'try'(
gcd(
erlang:element(2, Fr@2),
erlang:element(3, Fr@2)
),
fun(Gcd) -> {ok, {fraction, case Gcd of
0 -> 0;
Gleam@denominator -> erlang:element(
2,
Fr@2
)
div Gleam@denominator
end, case Gcd of
0 -> 0;
Gleam@denominator@1 -> erlang:element(
3,
Fr@2
)
div Gleam@denominator@1
end}} end
)
end)
end
)
end
).
-file("src/glib/fraction.gleam", 251).
-spec multiply(fraction(), fraction()) -> {ok, fraction()} |
{error, fraction_error()}.
multiply(Fr1, Fr2) ->
gleam@bool:guard(
(erlang:element(2, Fr1) =:= 0) orelse (erlang:element(2, Fr2) =:= 0),
{ok, {fraction, 0, 1}},
fun() ->
gleam@result:'try'(
gcd(erlang:element(2, Fr1), erlang:element(3, Fr2)),
fun(Gcd1) ->
gleam@result:'try'(
gcd(erlang:element(2, Fr2), erlang:element(3, Fr1)),
fun(Gcd2) -> gleam@result:'try'(mul_check(case Gcd1 of
0 -> 0;
Gleam@denominator -> erlang:element(
2,
Fr1
)
div Gleam@denominator
end, case Gcd2 of
0 -> 0;
Gleam@denominator@1 -> erlang:element(
2,
Fr2
)
div Gleam@denominator@1
end), fun(Multnum) ->
gleam@result:'try'(mul_pos(case Gcd2 of
0 -> 0;
Gleam@denominator@2 -> erlang:element(
3,
Fr1
)
div Gleam@denominator@2
end, case Gcd1 of
0 -> 0;
Gleam@denominator@3 -> erlang:element(
3,
Fr2
)
div Gleam@denominator@3
end), fun(Multden) ->
reduce({fraction, Multnum, Multden})
end)
end) end
)
end
)
end
).
-file("src/glib/fraction.gleam", 270).
-spec divide(fraction(), fraction()) -> {ok, fraction()} |
{error, fraction_error()}.
divide(Fr1, Fr2) ->
gleam@bool:guard(
erlang:element(2, Fr2) =:= 0,
{error, {divide_by_zero, <<""/utf8>>}},
fun() ->
gleam@result:'try'(
inverse(Fr2),
fun(Fr2_inv) -> multiply(Fr1, Fr2_inv) end
)
end
).
-file("src/glib/fraction.gleam", 277).
-spec power(fraction(), integer()) -> {ok, fraction()} |
{error, fraction_error()}.
power(Fr1, Pow) ->
gleam@bool:guard(
Pow =:= 1,
{ok, Fr1},
fun() ->
gleam@bool:guard(
Pow =:= 0,
{ok, {fraction, 1, 1}},
fun() -> case Pow < 0 of
true ->
case Pow =:= -9007199254740991 of
true ->
gleam@result:'try'(
inverse(Fr1),
fun(Inv) ->
gleam@result:'try'(
power(Inv, 2),
fun(Sq) ->
Half_pow = Pow div 2,
power(Sq, - Half_pow)
end
)
end
);
false ->
gleam@result:'try'(
inverse(Fr1),
fun(Inv@1) -> power(Inv@1, - Pow) end
)
end;
false ->
gleam@result:'try'(
multiply(Fr1, Fr1),
fun(Fr2) ->
gleam@result:'try'(
power(Fr2, Pow div 2),
fun(Half_pow@1) ->
case gleam@int:is_even(Pow) of
true ->
{ok, Half_pow@1};
false ->
multiply(Half_pow@1, Fr1)
end
end
)
end
)
end end
)
end
).
-file("src/glib/fraction.gleam", 342).
-spec add_or_sub(fraction(), fraction(), boolean()) -> {ok, fraction()} |
{error, fraction_error()}.
add_or_sub(Fr1, Fr2, Add) ->
gleam@bool:guard(erlang:element(2, Fr1) =:= 0, case Add of
true ->
{ok, Fr2};
false ->
negate(Fr2)
end, fun() ->
gleam@bool:guard(
erlang:element(2, Fr2) =:= 0,
{ok, Fr1},
fun() ->
gleam@result:'try'(
gcd(erlang:element(3, Fr1), erlang:element(3, Fr2)),
fun(Gcd1) ->
gleam@bool:guard(
Gcd1 =:= 1,
begin
gleam@result:'try'(
mul_check(
erlang:element(2, Fr1),
erlang:element(3, Fr2)
),
fun(Uvp) ->
gleam@result:'try'(
mul_check(
erlang:element(2, Fr2),
erlang:element(3, Fr1)
),
fun(Upv) ->
gleam@result:'try'(
case Add of
true ->
add_check(
Uvp,
Upv
);
false ->
sub_check(
Uvp,
Upv
)
end,
fun(New_numerator) ->
gleam@result:'try'(
mul_pos(
erlang:element(
3,
Fr1
),
erlang:element(
3,
Fr2
)
),
fun(
New_denominator
) ->
{ok,
{fraction,
New_numerator,
New_denominator}}
end
)
end
)
end
)
end
)
end,
fun() ->
Uvp@1 = erlang:element(2, Fr1) * (case Gcd1 of
0 -> 0;
Gleam@denominator -> erlang:element(
3,
Fr2
)
div Gleam@denominator
end),
Upv@1 = erlang:element(2, Fr2) * (case Gcd1 of
0 -> 0;
Gleam@denominator@1 -> erlang:element(
3,
Fr1
)
div Gleam@denominator@1
end),
T = case Add of
true ->
Uvp@1 + Upv@1;
false ->
Uvp@1 - Upv@1
end,
Tmod = case Gcd1 of
0 -> 0;
Gleam@denominator@2 -> T rem Gleam@denominator@2
end,
gleam@result:'try'(case Tmod =:= 0 of
true ->
{ok, Gcd1};
false ->
gcd(Tmod, Gcd1)
end, fun(Gcd2) ->
W = case Gcd2 of
0 -> 0;
Gleam@denominator@3 -> T div Gleam@denominator@3
end,
case (W > 9007199254740991) orelse (W
< -9007199254740991) of
true ->
{error,
{overflow,
<<(erlang:integer_to_binary(
W
))/binary,
" overflows"/utf8>>}};
false ->
gleam@result:'try'(
mul_pos(case Gcd1 of
0 -> 0;
Gleam@denominator@4 -> erlang:element(
3,
Fr1
)
div Gleam@denominator@4
end, case Gcd2 of
0 -> 0;
Gleam@denominator@5 -> erlang:element(
3,
Fr2
)
div Gleam@denominator@5
end),
fun(New_denominator@1) ->
{ok,
{fraction,
W,
New_denominator@1}}
end
)
end
end)
end
)
end
)
end
)
end).
-file("src/glib/fraction.gleam", 194).
-spec add(fraction(), fraction()) -> {ok, fraction()} |
{error, fraction_error()}.
add(Fr1, Fr2) ->
add_or_sub(Fr1, Fr2, true).
-file("src/glib/fraction.gleam", 198).
-spec sub(fraction(), fraction()) -> {ok, fraction()} |
{error, fraction_error()}.
sub(Fr1, Fr2) ->
add_or_sub(Fr1, Fr2, false).
-file("src/glib/fraction.gleam", 488).
-spec construct_fraction(integer(), integer(), float()) -> {ok, fraction()} |
{error, fraction_error()}.
construct_fraction(Sign, Whole, Value) ->
A = {internal_fraction,
{fraction, 0, 1},
{fraction, 1, 0},
0,
1.0,
Value,
+0.0,
1.7976931348623157e308},
Fr@2 = begin
_pipe = gleam@yielder:range(0, 24),
gleam@yielder:fold_until(
_pipe,
A,
fun(Fr, I) ->
Fr@1 = internal_calc(Value, Fr),
case ((erlang:element(7, Fr@1) > erlang:element(8, Fr@1))
andalso (erlang:element(3, erlang:element(3, Fr@1)) =< 10000))
andalso (erlang:element(3, erlang:element(3, Fr@1)) > 0) of
false ->
{stop, Fr@1};
true ->
case I of
24 ->
{stop,
begin
_record = A,
{internal_fraction,
{fraction, -1, -1},
erlang:element(3, _record),
erlang:element(4, _record),
erlang:element(5, _record),
erlang:element(6, _record),
erlang:element(7, _record),
erlang:element(8, _record)}
end};
_ ->
{continue, Fr@1}
end
end
end
)
end,
case Fr@2 of
{internal_fraction, {fraction, -1, -1}, _, _, _, _, _, _} ->
{error, {conversion_error, <<"Too many iterations"/utf8>>}};
_ ->
_pipe@1 = {fraction,
Sign * (erlang:element(2, erlang:element(2, Fr@2)) + (Whole * erlang:element(
3,
erlang:element(2, Fr@2)
))),
erlang:element(3, erlang:element(2, Fr@2))},
reduce(_pipe@1)
end.
-file("src/glib/fraction.gleam", 52).
?DOC(
" Generates a Fraction from given float\n"
" Returns error if number is larger than\n"
" the max int value\n"
" \n"
" ## Examples\n"
" \n"
" ```gleam\n"
" let fr = from_float(0.75)\n"
" // -> Ok(Fraction(3, 4))\n"
" ```\n"
" \n"
" ```gleam\n"
" let fr = from_float(0.66666)\n"
" // -> Ok(Fraction(2, 3))\n"
" ```\n"
).
-spec from_float(float()) -> {ok, fraction()} | {error, fraction_error()}.
from_float(Num) ->
Sign = case gleam@float:compare(Num, +0.0) of
lt ->
-1;
_ ->
1
end,
Num@1 = gleam@float:absolute_value(Num),
gleam@bool:guard(
Num@1 > erlang:float(9007199254740991),
{error, {too_large, <<"> 9007199254740991"/utf8>>}},
fun() ->
Whole = erlang:trunc(Num@1),
Num@2 = Num@1 - erlang:float(Whole),
construct_fraction(Sign, Whole, Num@2)
end
).
-file("src/glib/fraction.gleam", 125).
-spec from_string(binary()) -> {ok, fraction()} | {error, fraction_error()}.
from_string(Fraction) ->
case gleam_stdlib:contains_string(Fraction, <<"."/utf8>>) of
true ->
case gleam_stdlib:parse_float(Fraction) of
{ok, F} ->
from_float(F);
{error, _} ->
{error, {conversion_error, Fraction}}
end;
false ->
Parts = gleam@string:split(Fraction, <<" "/utf8>>),
case Parts of
[] ->
{ok, {fraction, 0, 1}};
[Whole, Fraction@1] ->
parse_with_whole(Whole, Fraction@1);
[Fraction@2] ->
case gleam_stdlib:parse_int(Fraction@2) of
{ok, F@1} ->
parse_with_whole(
erlang:integer_to_binary(F@1),
<<"0/1"/utf8>>
);
{error, _} ->
parse_fraction(Fraction@2)
end;
_ ->
{error, {conversion_error, Fraction}}
end
end.