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

jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New

Other popular topics Top

nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
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
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
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
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