Erlang: How to see a float in its actual bitwise representation?

This is a question about a rudimentary operation on the BEAM. That is why I’ve tagged it ‘Erlang’.

Recently, an issue came up on the repository of Rational, the elixir library providing rational numbers, about how floating-point numbers are converted into rational numbers.

The current implementation uses the Erlang primitive float_to_list, which returns a list with the decimal (so: base 10) representation of the number.

However, this is inherently imprecise, since floats are of course stored in the computer as base-2 (with a base-2 exponent and base-2 mantissa).

While for some contexts, this ‘lossy’ conversion is okay (and even desired), for other contexts it would make more sense to perform a ‘lossless’ conversion of the floating-point number to a rational number. For this I am thus looking to inspect the float as it is stored in its base-2 format.

Is there a way in Erlang/Elixir to do this?

3 Likes

Elixir:

iex> <<1.0::32>>
<<63, 128, 0, 0>>
iex> <<1.0::64>>
<<63, 240, 0, 0, 0, 0, 0, 0>>

You can also do the reverse. Source.

iex> <<x::float>> = <<63, 240, 0, 0, 0, 0, 0, 0>>  # this seems to default to 64 bits.
<<63, 240, 0, 0, 0, 0, 0, 0>>
iex> x
1.0
iex> <<x::float-size(64)>> = <<63, 240, 0, 0, 0, 0, 0, 0>>  # you can also explicitly set the float size.
<<63, 240, 0, 0, 0, 0, 0, 0>>
iex> x
1.0
iex> <<x::float-size(32)>> = <<63, 128, 0, 0>>
<<63, 128, 0, 0>>
iex> x
1.0
6 Likes

This gist might help in decoding floats and supporting your lossless rational objective.

4 Likes