dimitarvp

dimitarvp

Match floating point number in function head?

I am working on a protocol encoder & decoder. It has the quirk that if you wish to encode the maximum possible 64-bit floating point value then you don’t serialize it as all other values (namely the non-scientific full string representation) but only as a singular byte with the value zero.

Poking around on the net, and double-checking with Rust, I found that the value representing the maximum f64 has the byte representation of 0x7FEFFFFFFFFFFFFF. So we can decode it like so:

iex(1)> <<f::float-big-64>> = <<0x7FEFFFFFFFFFFFFF::unsigned-big-integer-64>>
<<127, 239, 255, 255, 255, 255, 255, 255>>
iex(2)> f
1.7976931348623157e308

Which looks (near-)identical to what Rust prints when you execute println!("{}", f64::MAX) in the Rust playground. So far, so good. But now I want to have an encoding function that recognizes the special value in its head and I can’t achieve it.

Obviously this does NOT work:

defmodule Codec do
  def encode_double(0x7FEFFFFFFFFFFFFF), do: <<0>>

  def encode_double(x) when is_float(x) do
    textual_float = Decimal.from_float(x) |> Decimal.to_string(:normal)
    textual_float <> <<0>>
  end
end

And this works just fine:

defmodule Codec do
  def encode_double(x) when is_float(x) do
    case <<x::float-big-64>> do
      # If the value is f64::MAX i.e. `0x7FEFFFFFFFFFFFFF`
      <<127, 239, 255, 255, 255, 255, 255, 255>> ->
        <<0>>

      _ ->
        textual_float = Decimal.from_float(x) |> Decimal.to_string(:normal)
        textual_float <> <<0>>
    end
  end
end

In the REPL:

iex(3)> Codec.encode_double f
<<0>>
iex(4)> Codec.encode_double 3.14
<<51, 46, 49, 52, 0>>

Is there a way to match on that special floating-point value in the function head? Mind you, that value must pass the is_float guard; if it wasn’t for that requirement I could have just used the byte array value in the function head.

Marked As Solved

al2o3cr

al2o3cr

You’d need to write the specific value out:

defmodule Blah do
  def foo(1.7976931348623157e308), do: :nope
  def foo(_x), do: :ok
end

<<f::float-big-64>> = <<0x7FEFFFFFFFFFFFFF::unsigned-big-integer-64>>
Blah.foo(f) # => :nope

<<f2::float-big-64>> = <<0x7FEFFFFFFFFFFFFE::unsigned-big-integer-64>>
Blah.foo(f2) # => :ok

IMO that format seems very strange; there’s a whole category of floats sitting right there (the NaNs / 0x7FF...s) that make better sentinel values.

Last Post!

al2o3cr

al2o3cr

The next-smallest possible floating point value is 1.7976931348623155e+308 to the same precision - 1.99584030953472e292 smaller. A parser that can’t tell the difference is broken! :stuck_out_tongue:

Where Next?

Popular in Questions Top

minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New

Other popular topics Top

joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 31586 112
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 44778 311
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 42716 114
New

We're in Beta

About us Mission Statement