Skip to content

Instantly share code, notes, and snippets.

@kipcole9
Created January 2, 2020 13:05
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kipcole9/67409ee80a4465ab694af4a467f60e94 to your computer and use it in GitHub Desktop.
Save kipcole9/67409ee80a4465ab694af4a467f60e94 to your computer and use it in GitHub Desktop.
Decode a float in Elixir
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