-module(ieee_float). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([finite/1, positive_infinity/0, negative_infinity/0, nan/0, is_finite/1, is_nan/1, to_finite/1, to_string/1, parse/1, to_bytes_32_le/1, from_bytes_32_le/1, to_bytes_32_be/1, from_bytes_32_be/1, to_bytes_64_le/1, from_bytes_64_le/1, to_bytes_64_be/1, from_bytes_64_be/1, absolute_value/1, add/2, ceiling/1, compare/2, divide/2, floor/1, max/2, min/2, clamp/3, multiply/2, negate/1, power/2, random/0, round/1, square_root/1, subtract/2]). -export_type([ieee_float/0, sign/0]). -opaque ieee_float() :: {finite, float()} | {infinite, sign()} | na_n. -type sign() :: positive | negative. -spec finite(float()) -> ieee_float(). finite(F) -> {finite, F}. -spec positive_infinity() -> ieee_float(). positive_infinity() -> {infinite, positive}. -spec negative_infinity() -> ieee_float(). negative_infinity() -> {infinite, negative}. -spec nan() -> ieee_float(). nan() -> na_n. -spec is_finite(ieee_float()) -> boolean(). is_finite(F) -> case F of {finite, _} -> true; _ -> false end. -spec is_nan(ieee_float()) -> boolean(). is_nan(F) -> F =:= na_n. -spec to_finite(ieee_float()) -> {ok, float()} | {error, nil}. to_finite(F) -> case F of {finite, Value} -> {ok, Value}; _ -> {error, nil} end. -spec to_string(ieee_float()) -> binary(). to_string(F) -> case F of {finite, F@1} -> gleam@float:to_string(F@1); {infinite, positive} -> <<"Infinity"/utf8>>; {infinite, negative} -> <<"-Infinity"/utf8>>; na_n -> <<"NaN"/utf8>> end. -spec parse(binary()) -> ieee_float(). parse(S) -> case gleam@string:trim(S) of <<"Infinity"/utf8>> -> {infinite, positive}; <<"-Infinity"/utf8>> -> {infinite, negative}; S@1 -> case gleam@float:parse(S@1) of {ok, F} -> {finite, F}; _ -> na_n end end. -spec to_bytes_32_le(ieee_float()) -> bitstring(). to_bytes_32_le(F) -> case F of {finite, F@1} -> <>; {infinite, positive} -> <<16#7F800000:32/little>>; {infinite, negative} -> <<16#FF800000:32/little>>; na_n -> <<16#7FC00000:32/little>> end. -spec from_bytes_32_le(bitstring()) -> ieee_float(). from_bytes_32_le(Bytes) -> case Bytes of <> -> {finite, Value}; <<16#7F800000:32/little>> -> {infinite, positive}; <<16#FF800000:32/little>> -> {infinite, negative}; _ -> na_n end. -spec to_bytes_32_be(ieee_float()) -> bitstring(). to_bytes_32_be(F) -> case F of {finite, F@1} -> <>; {infinite, positive} -> <<16#7F800000:32/big>>; {infinite, negative} -> <<16#FF800000:32/big>>; na_n -> <<16#7FC00000:32/big>> end. -spec from_bytes_32_be(bitstring()) -> ieee_float(). from_bytes_32_be(Bytes) -> case Bytes of <> -> {finite, Value}; <<16#7F800000:32/big>> -> {infinite, positive}; <<16#FF800000:32/big>> -> {infinite, negative}; _ -> na_n end. -spec to_bytes_64_le(ieee_float()) -> bitstring(). to_bytes_64_le(F) -> case F of {finite, F@1} -> <>; {infinite, positive} -> <<16#7FF0000000000000:64/little>>; {infinite, negative} -> <<16#FFF0000000000000:64/little>>; na_n -> <<16#7FF8000000000000:64/little>> end. -spec from_bytes_64_le(bitstring()) -> ieee_float(). from_bytes_64_le(Bytes) -> case Bytes of <> -> {finite, Value}; <<16#7FF0000000000000:64/little>> -> {infinite, positive}; <<16#FFF0000000000000:64/little>> -> {infinite, negative}; _ -> na_n end. -spec to_bytes_64_be(ieee_float()) -> bitstring(). to_bytes_64_be(F) -> case F of {finite, F@1} -> <>; {infinite, positive} -> <<16#7FF0000000000000:64/big>>; {infinite, negative} -> <<16#FFF0000000000000:64/big>>; na_n -> <<16#7FF8000000000000:64/big>> end. -spec from_bytes_64_be(bitstring()) -> ieee_float(). from_bytes_64_be(Bytes) -> case Bytes of <> -> {finite, Value}; <<16#7FF0000000000000:64/big>> -> {infinite, positive}; <<16#FFF0000000000000:64/big>> -> {infinite, negative}; _ -> na_n end. -spec rescue_bad_arith(fun(() -> OCA)) -> {ok, OCA} | {error, nil}. rescue_bad_arith(Do) -> case gleam_erlang_ffi:rescue(Do) of {ok, R} -> {ok, R}; {error, {errored, Reason}} -> case begin _pipe = gleam_erlang_ffi:atom_from_dynamic(Reason), gleam@result:map(_pipe, fun erlang:atom_to_binary/1) end =:= {ok, <<"badarith"/utf8>>} of true -> {error, nil}; false -> erlang:error(#{gleam_error => panic, message => (<<"Unexpected error in float operation: "/utf8, (gleam@string:inspect(Reason))/binary>>), module => <<"ieee_float"/utf8>>, function => <<"rescue_bad_arith"/utf8>>, line => 228}) end; {error, E} -> erlang:error(#{gleam_error => panic, message => (<<"Unexpected error in float operation: "/utf8, (gleam@string:inspect(E))/binary>>), module => <<"ieee_float"/utf8>>, function => <<"rescue_bad_arith"/utf8>>, line => 234}) end. -spec absolute_value(ieee_float()) -> ieee_float(). absolute_value(F) -> case F of {finite, F@1} -> _pipe = F@1, _pipe@1 = gleam@float:absolute_value(_pipe), {finite, _pipe@1}; {infinite, _} -> {infinite, positive}; na_n -> na_n end. -spec add(ieee_float(), ieee_float()) -> ieee_float(). add(A, B) -> case {A, B} of {{finite, A@1}, {finite, B@1}} -> case rescue_bad_arith(fun() -> {finite, A@1 + B@1} end) of {ok, F} -> F; {error, nil} -> case {A@1 >= +0.0, B@1 >= +0.0} of {true, true} -> {infinite, positive}; {false, false} -> {infinite, negative}; {_, _} -> erlang:error(#{gleam_error => panic, message => <<"Unexpected error in ieee_float.add"/utf8>>, module => <<"ieee_float"/utf8>>, function => <<"add"/utf8>>, line => 261}) end end; {{infinite, Sign}, {finite, _}} -> {infinite, Sign}; {{finite, _}, {infinite, Sign@1}} -> {infinite, Sign@1}; {{infinite, positive}, {infinite, positive}} -> {infinite, positive}; {{infinite, negative}, {infinite, negative}} -> {infinite, negative}; {{infinite, positive}, {infinite, negative}} -> na_n; {{infinite, negative}, {infinite, positive}} -> na_n; {na_n, _} -> na_n; {_, na_n} -> na_n end. -spec ceiling(ieee_float()) -> ieee_float(). ceiling(F) -> case F of {finite, F@1} -> _pipe = F@1, _pipe@1 = gleam@float:ceiling(_pipe), {finite, _pipe@1}; _ -> F end. -spec compare(ieee_float(), ieee_float()) -> {ok, gleam@order:order()} | {error, nil}. compare(A, B) -> case {A, B} of {{finite, A@1}, {finite, B@1}} -> {ok, gleam@float:compare(A@1, B@1)}; {{finite, _}, {infinite, positive}} -> {ok, lt}; {{infinite, positive}, {finite, _}} -> {ok, gt}; {{finite, _}, {infinite, negative}} -> {ok, gt}; {{infinite, negative}, {finite, _}} -> {ok, lt}; {{infinite, negative}, {infinite, negative}} -> {ok, eq}; {{infinite, negative}, {infinite, positive}} -> {ok, lt}; {{infinite, positive}, {infinite, negative}} -> {ok, gt}; {{infinite, positive}, {infinite, positive}} -> {ok, eq}; {na_n, _} -> {error, nil}; {_, na_n} -> {error, nil} end. -spec divide(ieee_float(), ieee_float()) -> ieee_float(). divide(A, B) -> case {A, B} of {na_n, _} -> na_n; {_, na_n} -> na_n; {{finite, +0.0}, {finite, +0.0}} -> na_n; {{finite, +0.0}, {finite, -0.0}} -> na_n; {{finite, -0.0}, {finite, +0.0}} -> na_n; {{finite, -0.0}, {finite, -0.0}} -> na_n; {{finite, A@1}, {finite, +0.0}} -> case A@1 < +0.0 of true -> {infinite, negative}; false -> {infinite, positive} end; {{finite, A@2}, {finite, -0.0}} -> case A@2 < +0.0 of true -> {infinite, positive}; false -> {infinite, negative} end; {{finite, A@3}, {finite, B@1}} -> case rescue_bad_arith(fun() -> {finite, case B@1 of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator -> A@3 / Gleam@denominator end} end) of {ok, F} -> F; {error, nil} -> case (A@3 >= +0.0) =:= (B@1 >= +0.0) of true -> {infinite, positive}; false -> {infinite, negative} end end; {{finite, A@4}, {infinite, positive}} -> case A@4 >= +0.0 of true -> {finite, +0.0}; false -> {finite, -0.0} end; {{finite, A@5}, {infinite, negative}} -> case A@5 >= +0.0 of true -> {finite, -0.0}; false -> {finite, +0.0} end; {{infinite, positive}, {finite, B@2}} -> case B@2 >= +0.0 of true -> {infinite, positive}; false -> {infinite, negative} end; {{infinite, negative}, {finite, B@3}} -> case B@3 >= +0.0 of true -> {infinite, negative}; false -> {infinite, positive} end; {{infinite, _}, {infinite, _}} -> na_n end. -spec floor(ieee_float()) -> ieee_float(). floor(F) -> case F of {finite, F@1} -> _pipe = F@1, _pipe@1 = gleam@float:floor(_pipe), {finite, _pipe@1}; _ -> F end. -spec max(ieee_float(), ieee_float()) -> ieee_float(). max(A, B) -> case {A, B} of {{finite, A@1}, {finite, B@1}} -> _pipe = gleam@float:max(A@1, B@1), {finite, _pipe}; {{infinite, positive}, _} -> {infinite, positive}; {_, {infinite, positive}} -> {infinite, positive}; {{infinite, negative}, A@2} -> A@2; {A@2, {infinite, negative}} -> A@2; {na_n, _} -> na_n; {_, na_n} -> na_n end. -spec min(ieee_float(), ieee_float()) -> ieee_float(). min(A, B) -> case {A, B} of {{finite, A@1}, {finite, B@1}} -> _pipe = gleam@float:min(A@1, B@1), {finite, _pipe}; {{infinite, negative}, _} -> {infinite, negative}; {_, {infinite, negative}} -> {infinite, negative}; {{infinite, positive}, A@2} -> A@2; {A@2, {infinite, positive}} -> A@2; {na_n, _} -> na_n; {_, na_n} -> na_n end. -spec clamp(ieee_float(), ieee_float(), ieee_float()) -> ieee_float(). clamp(F, Min_bound, Max_bound) -> _pipe = F, _pipe@1 = min(_pipe, Max_bound), max(_pipe@1, Min_bound). -spec multiply(ieee_float(), ieee_float()) -> ieee_float(). multiply(A, B) -> case {A, B} of {na_n, _} -> na_n; {_, na_n} -> na_n; {{finite, A@1}, {finite, B@1}} -> case rescue_bad_arith(fun() -> {finite, A@1 * B@1} end) of {ok, F} -> F; {error, nil} -> case (A@1 >= +0.0) =:= (B@1 >= +0.0) of true -> {infinite, positive}; false -> {infinite, negative} end end; {{infinite, positive}, {finite, F@1}} -> case F@1 >= +0.0 of true -> {infinite, positive}; false -> {infinite, negative} end; {{finite, F@1}, {infinite, positive}} -> case F@1 >= +0.0 of true -> {infinite, positive}; false -> {infinite, negative} end; {{infinite, negative}, {finite, F@2}} -> case F@2 >= +0.0 of true -> {infinite, negative}; false -> {infinite, positive} end; {{finite, F@2}, {infinite, negative}} -> case F@2 >= +0.0 of true -> {infinite, negative}; false -> {infinite, positive} end; {{infinite, A@2}, {infinite, B@2}} -> case A@2 =:= B@2 of true -> {infinite, positive}; false -> {infinite, negative} end end. -spec negate(ieee_float()) -> ieee_float(). negate(F) -> case F of {finite, F@1} -> _pipe = F@1, _pipe@1 = gleam@float:negate(_pipe), {finite, _pipe@1}; {infinite, positive} -> {infinite, negative}; {infinite, negative} -> {infinite, positive}; na_n -> na_n end. -spec power(ieee_float(), ieee_float()) -> ieee_float(). power(F, Exp) -> case {F, Exp} of {{finite, F@1}, {finite, Exp@1}} -> case rescue_bad_arith(fun() -> gleam@float:power(F@1, Exp@1) end) of {ok, F@2} -> _pipe = F@2, _pipe@1 = gleam@result:map( _pipe, fun(Field@0) -> {finite, Field@0} end ), gleam@result:unwrap(_pipe@1, na_n); {error, nil} -> {infinite, positive} end; {na_n, _} -> na_n; {_, na_n} -> na_n; {{infinite, _}, {finite, +0.0}} -> {finite, 1.0}; {{infinite, _}, {finite, -0.0}} -> {finite, 1.0}; {{finite, 1.0}, {infinite, _}} -> na_n; {{finite, -1.0}, {infinite, _}} -> na_n; {{infinite, positive}, {infinite, positive}} -> {infinite, positive}; {{infinite, positive}, {infinite, negative}} -> {finite, +0.0}; {{infinite, negative}, {infinite, positive}} -> {infinite, positive}; {{infinite, negative}, {infinite, negative}} -> {finite, +0.0}; {{infinite, positive}, {finite, F@3}} when F@3 < +0.0 -> {finite, +0.0}; {{finite, +0.0}, {infinite, positive}} -> {finite, +0.0}; {{finite, -0.0}, {infinite, positive}} -> {finite, +0.0}; {{finite, _}, {infinite, positive}} -> {infinite, positive}; {{infinite, positive}, {finite, _}} -> {infinite, positive}; {{finite, F@4}, {infinite, negative}} -> case (F@4 > 1.0) orelse (F@4 < -1.0) of true -> {finite, +0.0}; false -> {infinite, positive} end; {{infinite, negative}, {finite, F@5}} -> case (gleam@int:to_float(gleam@float:round(F@5)) =:= F@5) andalso gleam@int:is_odd( gleam@float:truncate(F@5) ) of true -> case F@5 < +0.0 of true -> {finite, -0.0}; false -> {infinite, negative} end; false -> case F@5 < +0.0 of true -> {finite, +0.0}; false -> {infinite, positive} end end end. -spec random() -> ieee_float(). random() -> {finite, rand:uniform()}. -spec round(ieee_float()) -> {ok, integer()} | {error, nil}. round(F) -> case F of {finite, F@1} -> _pipe = F@1, _pipe@1 = gleam@float:round(_pipe), {ok, _pipe@1}; _ -> {error, nil} end. -spec square_root(ieee_float()) -> ieee_float(). square_root(F) -> power(F, {finite, 0.5}). -spec subtract(ieee_float(), ieee_float()) -> ieee_float(). subtract(A, B) -> add(A, negate(B)).