Created
January 2, 2020 13:05
-
-
Save kipcole9/67409ee80a4465ab694af4a467f60e94 to your computer and use it in GitHub Desktop.
Decode a float in Elixir
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Decode do | |
@moduledoc """ | |
Extracted from https://github.com/ewildgoose/elixir-float_pp | |
""" | |
use Bitwise | |
@float_bias 1022 | |
############################################################################ | |
# Utility functions | |
@doc """ | |
The frexp() function is as per the clib function with the same name. It breaks | |
the floating-point number value into a normalized fraction and an integral | |
power of 2. | |
Returns {frac, exp}, where the magnitude of frac is in the interval | |
[1/2, 1) or 0, and value = frac*(2^exp). | |
FIXME: We don't handle +/-inf and NaN inputs. Not believed to be an issue in | |
Elixir, but beware future-self reading this... | |
""" | |
def frexp(value) do | |
<< sign::1, exp::11, frac::52 >> = << value::float >> | |
frexp(sign, frac, exp) | |
end | |
defp frexp(_Sign, 0, 0) do | |
{0.0, 0} | |
end | |
# Handle denormalised values | |
defp frexp(sign, frac, 0) do | |
exp = bitwise_length(frac) | |
<<f::float>> = <<sign::1, @float_bias::11, (frac-1)::52>> | |
{f, -(@float_bias) - 52 + exp} | |
end | |
# Handle normalised values | |
defp frexp(sign, frac, exp) do | |
<<f::float>> = <<sign::1, @float_bias::11, frac::52>> | |
{f, exp - @float_bias} | |
end | |
@doc """ | |
Return the number of significant bits needed to store the given number | |
""" | |
def bitwise_length(value) do | |
bitwise_length(value, 0) | |
end | |
defp bitwise_length(0, n), do: n | |
defp bitwise_length(value, n), do: bitwise_length(bsr(value, 1), n+1) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment