Current section

Files

Jump to
ieee_float src ieee_float.erl
Raw

src/ieee_float.erl

-module(ieee_float).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/ieee_float.gleam").
-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_16_le/1, from_bytes_16_le/1, to_bytes_16_be/1, from_bytes_16_be/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([i_e_e_e_float/0, sign/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.
-opaque i_e_e_e_float() :: {finite, float()} | {infinite, sign()} | na_n.
-type sign() :: positive | negative.
-file("src/ieee_float.gleam", 28).
?DOC(" Creates a new `IEEEFloat` from a `Float`.\n").
-spec finite(float()) -> i_e_e_e_float().
finite(F) ->
{finite, F}.
-file("src/ieee_float.gleam", 35).
?DOC(" Returns the positive infinity value.\n").
-spec positive_infinity() -> i_e_e_e_float().
positive_infinity() ->
{infinite, positive}.
-file("src/ieee_float.gleam", 42).
?DOC(" Returns the negative infinity value.\n").
-spec negative_infinity() -> i_e_e_e_float().
negative_infinity() ->
{infinite, negative}.
-file("src/ieee_float.gleam", 49).
?DOC(" Returns the NaN (Not a Number) value.\n").
-spec nan() -> i_e_e_e_float().
nan() ->
na_n.
-file("src/ieee_float.gleam", 57).
?DOC(
" Returns whether an `IEEEFloat` is finite. If it isn't finite it is either\n"
" infinite or NaN.\n"
).
-spec is_finite(i_e_e_e_float()) -> boolean().
is_finite(F) ->
case F of
{finite, _} ->
true;
_ ->
false
end.
-file("src/ieee_float.gleam", 68).
?DOC(
" Returns whether an `IEEEFloat` is NaN. If it isn't NaN it is either finite\n"
" or infinite.\n"
).
-spec is_nan(i_e_e_e_float()) -> boolean().
is_nan(F) ->
F =:= na_n.
-file("src/ieee_float.gleam", 76).
?DOC(
" Converts an `IEEEFloat` to the native `Float` type. If the `IEEEFloat` is\n"
" infinite or NaN then `Error(Nil)` is returned.\n"
).
-spec to_finite(i_e_e_e_float()) -> {ok, float()} | {error, nil}.
to_finite(F) ->
case F of
{finite, Value} ->
{ok, Value};
_ ->
{error, nil}
end.
-file("src/ieee_float.gleam", 86).
?DOC(" Formats an `IEEEFloat` as a string.\n").
-spec to_string(i_e_e_e_float()) -> binary().
to_string(F) ->
case F of
{finite, F@1} ->
gleam_stdlib:float_to_string(F@1);
{infinite, positive} ->
<<"Infinity"/utf8>>;
{infinite, negative} ->
<<"-Infinity"/utf8>>;
na_n ->
<<"NaN"/utf8>>
end.
-file("src/ieee_float.gleam", 99).
?DOC(
" Parses a string to an `IEEEFloat`. If the string is not a valid float then\n"
" NaN is returned.\n"
).
-spec parse(binary()) -> i_e_e_e_float().
parse(S) ->
case gleam@string:trim(S) of
<<"Infinity"/utf8>> ->
{infinite, positive};
<<"-Infinity"/utf8>> ->
{infinite, negative};
S@1 ->
case gleam_stdlib:parse_float(S@1) of
{ok, F} ->
{finite, F};
_ ->
na_n
end
end.
-file("src/ieee_float.gleam", 114).
?DOC(" Converts an `IEEEFloat` to bytes for a little endian 16-bit IEEE 754 float.\n").
-spec to_bytes_16_le(i_e_e_e_float()) -> bitstring().
to_bytes_16_le(F) ->
case F of
{finite, F@1} ->
<<F@1:16/float-little>>;
{infinite, positive} ->
<<16#7C00:16/little>>;
{infinite, negative} ->
<<16#FC00:16/little>>;
na_n ->
<<16#7E00:16/little>>
end.
-file("src/ieee_float.gleam", 128).
?DOC(
" Converts bytes for a little endian 16-bit IEEE 754 float to an `IEEEFloat`.\n"
"\n"
" If the bit array doesn't contain exactly two bytes then NaN is returned.\n"
).
-spec from_bytes_16_le(bitstring()) -> i_e_e_e_float().
from_bytes_16_le(Bytes) ->
case Bytes of
<<Value:16/float-little>> ->
{finite, Value};
<<16#7C00:16/little>> ->
{infinite, positive};
<<16#FC00:16/little>> ->
{infinite, negative};
_ ->
na_n
end.
-file("src/ieee_float.gleam", 140).
?DOC(" Converts an `IEEEFloat` to bytes for a big endian 16-bit IEEE 754 float.\n").
-spec to_bytes_16_be(i_e_e_e_float()) -> bitstring().
to_bytes_16_be(F) ->
case F of
{finite, F@1} ->
<<F@1:16/float>>;
{infinite, positive} ->
<<16#7C00:16>>;
{infinite, negative} ->
<<16#FC00:16>>;
na_n ->
<<16#7E00:16>>
end.
-file("src/ieee_float.gleam", 154).
?DOC(
" Converts bytes for a big endian 16-bit IEEE 754 float to an `IEEEFloat`.\n"
"\n"
" If the bit array doesn't contain exactly two bytes then NaN is returned.\n"
).
-spec from_bytes_16_be(bitstring()) -> i_e_e_e_float().
from_bytes_16_be(Bytes) ->
case Bytes of
<<Value:16/float>> ->
{finite, Value};
<<16#7C00:16>> ->
{infinite, positive};
<<16#FC00:16>> ->
{infinite, negative};
_ ->
na_n
end.
-file("src/ieee_float.gleam", 166).
?DOC(" Converts an `IEEEFloat` to bytes for a little endian 32-bit IEEE 754 float.\n").
-spec to_bytes_32_le(i_e_e_e_float()) -> bitstring().
to_bytes_32_le(F) ->
case F of
{finite, F@1} ->
<<F@1:32/float-little>>;
{infinite, positive} ->
<<16#7F800000:32/little>>;
{infinite, negative} ->
<<16#FF800000:32/little>>;
na_n ->
<<16#7FC00000:32/little>>
end.
-file("src/ieee_float.gleam", 180).
?DOC(
" Converts bytes for a little endian 32-bit IEEE 754 float to an `IEEEFloat`.\n"
"\n"
" If the bit array doesn't contain exactly four bytes then NaN is returned.\n"
).
-spec from_bytes_32_le(bitstring()) -> i_e_e_e_float().
from_bytes_32_le(Bytes) ->
case Bytes of
<<Value:32/float-little>> ->
{finite, Value};
<<16#7F800000:32/little>> ->
{infinite, positive};
<<16#FF800000:32/little>> ->
{infinite, negative};
_ ->
na_n
end.
-file("src/ieee_float.gleam", 192).
?DOC(" Converts an `IEEEFloat` to bytes for a big endian 32-bit IEEE 754 float.\n").
-spec to_bytes_32_be(i_e_e_e_float()) -> bitstring().
to_bytes_32_be(F) ->
case F of
{finite, F@1} ->
<<F@1:32/float>>;
{infinite, positive} ->
<<16#7F800000:32>>;
{infinite, negative} ->
<<16#FF800000:32>>;
na_n ->
<<16#7FC00000:32>>
end.
-file("src/ieee_float.gleam", 206).
?DOC(
" Converts bytes for a big endian 32-bit IEEE 754 float to an `IEEEFloat`.\n"
"\n"
" If the bit array doesn't contain exactly four bytes then NaN is returned.\n"
).
-spec from_bytes_32_be(bitstring()) -> i_e_e_e_float().
from_bytes_32_be(Bytes) ->
case Bytes of
<<Value:32/float>> ->
{finite, Value};
<<16#7F800000:32>> ->
{infinite, positive};
<<16#FF800000:32>> ->
{infinite, negative};
_ ->
na_n
end.
-file("src/ieee_float.gleam", 218).
?DOC(" Converts an `IEEEFloat` to bytes for a little endian 64-bit IEEE 754 float.\n").
-spec to_bytes_64_le(i_e_e_e_float()) -> bitstring().
to_bytes_64_le(F) ->
case F of
{finite, F@1} ->
<<F@1:64/float-little>>;
{infinite, positive} ->
<<16#7FF0000000000000:64/little>>;
{infinite, negative} ->
<<16#FFF0000000000000:64/little>>;
na_n ->
<<16#7FF8000000000000:64/little>>
end.
-file("src/ieee_float.gleam", 232).
?DOC(
" Converts bytes for a little endian 64-bit IEEE 754 float to an `IEEEFloat`.\n"
"\n"
" If the bit array doesn't contain exactly eight bytes then NaN is returned.\n"
).
-spec from_bytes_64_le(bitstring()) -> i_e_e_e_float().
from_bytes_64_le(Bytes) ->
case Bytes of
<<Value:64/float-little>> ->
{finite, Value};
<<16#7FF0000000000000:64/little>> ->
{infinite, positive};
<<16#FFF0000000000000:64/little>> ->
{infinite, negative};
_ ->
na_n
end.
-file("src/ieee_float.gleam", 244).
?DOC(" Converts an `IEEEFloat` to bytes for a big endian 64-bit IEEE 754 float.\n").
-spec to_bytes_64_be(i_e_e_e_float()) -> bitstring().
to_bytes_64_be(F) ->
case F of
{finite, F@1} ->
<<F@1:64/float>>;
{infinite, positive} ->
<<16#7FF0000000000000:64>>;
{infinite, negative} ->
<<16#FFF0000000000000:64>>;
na_n ->
<<16#7FF8000000000000:64>>
end.
-file("src/ieee_float.gleam", 258).
?DOC(
" Converts bytes for a big endian 64-bit IEEE 754 float to an `IEEEFloat`.\n"
"\n"
" If the bit array doesn't contain exactly eight bytes then NaN is returned.\n"
).
-spec from_bytes_64_be(bitstring()) -> i_e_e_e_float().
from_bytes_64_be(Bytes) ->
case Bytes of
<<Value:64/float>> ->
{finite, Value};
<<16#7FF0000000000000:64>> ->
{infinite, positive};
<<16#FFF0000000000000:64>> ->
{infinite, negative};
_ ->
na_n
end.
-file("src/ieee_float.gleam", 281).
?DOC(" Returns the absolute value of an `IEEEFloat`.\n").
-spec absolute_value(i_e_e_e_float()) -> i_e_e_e_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.
-file("src/ieee_float.gleam", 292).
?DOC(" Adds two `IEEEFloat`s together.\n").
-spec add(i_e_e_e_float(), i_e_e_e_float()) -> i_e_e_e_float().
add(A, B) ->
case {A, B} of
{{finite, A@1}, {finite, B@1}} ->
case ieee_float_ffi: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>>,
file => <<?FILEPATH/utf8>>,
module => <<"ieee_float"/utf8>>,
function => <<"add"/utf8>>,
line => 301})
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.
-file("src/ieee_float.gleam", 321).
?DOC(" Rounds an `IEEEFloat` to the next highest whole number.\n").
-spec ceiling(i_e_e_e_float()) -> i_e_e_e_float().
ceiling(F) ->
case F of
{finite, F@1} ->
_pipe = F@1,
_pipe@1 = math:ceil(_pipe),
{finite, _pipe@1};
_ ->
F
end.
-file("src/ieee_float.gleam", 345).
?DOC(
" Compares two `IEEEFloat`s, returning an `Order`: `Lt` for lower than, `Eq`\n"
" for equals, or `Gt` for greater than. If either value is NaN then\n"
" `Error(Nil)` is returned.\n"
).
-spec compare(i_e_e_e_float(), i_e_e_e_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.
-file("src/ieee_float.gleam", 366).
?DOC(" Divides one `IEEEFloat` by another.\n").
-spec divide(i_e_e_e_float(), i_e_e_e_float()) -> i_e_e_e_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 ieee_float_ffi: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.
-file("src/ieee_float.gleam", 429).
?DOC(" Rounds an `IEEEFloat` to the next lowest whole number.\n").
-spec floor(i_e_e_e_float()) -> i_e_e_e_float().
floor(F) ->
case F of
{finite, F@1} ->
_pipe = F@1,
_pipe@1 = math:floor(_pipe),
{finite, _pipe@1};
_ ->
F
end.
-file("src/ieee_float.gleam", 439).
?DOC(" Compares two `IEEEFloat`s, returning the larger of the two.\n").
-spec max(i_e_e_e_float(), i_e_e_e_float()) -> i_e_e_e_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.
-file("src/ieee_float.gleam", 451).
?DOC(" Compares two `IEEEFloat`s, returning the smaller of the two.\n").
-spec min(i_e_e_e_float(), i_e_e_e_float()) -> i_e_e_e_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.
-file("src/ieee_float.gleam", 330).
?DOC(" Restricts an `IEEEFloat` between a lower and upper bound.\n").
-spec clamp(i_e_e_e_float(), i_e_e_e_float(), i_e_e_e_float()) -> i_e_e_e_float().
clamp(F, Min_bound, Max_bound) ->
_pipe = F,
_pipe@1 = min(_pipe, Max_bound),
max(_pipe@1, Min_bound).
-file("src/ieee_float.gleam", 463).
?DOC(" Multiplies two `IEEEFloat`s together.\n").
-spec multiply(i_e_e_e_float(), i_e_e_e_float()) -> i_e_e_e_float().
multiply(A, B) ->
case {A, B} of
{na_n, _} ->
na_n;
{_, na_n} ->
na_n;
{{finite, A@1}, {finite, B@1}} ->
case ieee_float_ffi: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.
-file("src/ieee_float.gleam", 500).
?DOC(" Returns the negative of an `IEEEFloat`.\n").
-spec negate(i_e_e_e_float()) -> i_e_e_e_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.
-file("src/ieee_float.gleam", 512).
?DOC(" Returns the results of the base being raised to the power of the exponent.\n").
-spec power(i_e_e_e_float(), i_e_e_e_float()) -> i_e_e_e_float().
power(F, Exp) ->
case {F, Exp} of
{{finite, F@1}, {finite, Exp@1}} ->
case ieee_float_ffi: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 (erlang:float(erlang:round(F@5)) =:= F@5) andalso gleam@int:is_odd(
erlang:trunc(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.
-file("src/ieee_float.gleam", 577).
?DOC(
" Generates a random `IEEEFloat` between zero (inclusive) and one (exclusive).\n"
"\n"
" On the Erlang target this updates the random state in the process\n"
" dictionary. See <https://www.erlang.org/doc/man/rand.html#uniform-0>.\n"
).
-spec random() -> i_e_e_e_float().
random() ->
{finite, rand:uniform()}.
-file("src/ieee_float.gleam", 585).
?DOC(
" Rounds an `IEEEFloat` to the nearest whole number as an `Int`. If the input\n"
" value is not finite then `Error(Nil)` is returned.\n"
).
-spec round(i_e_e_e_float()) -> {ok, integer()} | {error, nil}.
round(F) ->
case F of
{finite, F@1} ->
_pipe = F@1,
_pipe@1 = erlang:round(_pipe),
{ok, _pipe@1};
_ ->
{error, nil}
end.
-file("src/ieee_float.gleam", 595).
?DOC(" Returns the square root of an `IEEEFloat`.\n").
-spec square_root(i_e_e_e_float()) -> i_e_e_e_float().
square_root(F) ->
power(F, {finite, 0.5}).
-file("src/ieee_float.gleam", 602).
?DOC(" Subtracts one `IEEEFloat` from another.\n").
-spec subtract(i_e_e_e_float(), i_e_e_e_float()) -> i_e_e_e_float().
subtract(A, B) ->
add(A, negate(B)).