benlime

benlime

How to encode Decimal with Jason Library to float?

Hey guys,

I have a short and simple question, which I am currently unable to figure out using the documentation of the Jason library.

I have a struct which contains some keys with values of the Decimal struct. I would like to have the Decimal struct (I am using the Decimal Library for it) always converted to float when encoding to JSON. So far I only know that I would have to implement the Json.Encoder protocol and have the encode method to call Decimal.to_float(value). But I am not sure how to do that? How do I implement the protocol?

I have tried to just make a file like this:

defimpl Jason.Encoder, for: Decimal do
  def encode(struct, opts) do
    Jason.Encode.map(Decimal.to_float(struct), opts)
  end
end

However, this code never runs. Can anybod help? :slight_smile:

Thanks guys.

First Post!

NobbZ

NobbZ

Please do not use floats. You will use all the precision you initially got by using decimal. Please do either use a String or dump into a JSON object.

Aside of that, you should use Jason.Encode.float/1. From what I can see in the snippet you posted, the code should crash rather than not being run. Can you therefore reproduce the problem in a fresh project and put it on github?

Most Liked

NobbZ

NobbZ

Floating point numbers might have their right to exist in JSON, but definitively not when your datasource is a Decimal, as Decimal allows for very exact values, which float doesn’t.

This is good.

But to be honest, in JSON the only way to represent numbers in a safe way, as JSON does not differentiate between integers and floats, but knows only about numbers. So numbers that look integral might get coerced to float without you beeing able to control.

From jason:

https://github.com/michalmuskala/jason/blob/master/lib/encoder.ex#L204-L210

So you can not change it.

And here we already have a problem. What is encoded as 1 Euro and 5 cent might get rendered as 1.05 in the JSON, but as this probably not an exact value in Float this might get loaded as 1.04999999 (or similar) and displayed as such. Or even worse, the client truncates or rounds, or does other things out of your control.

Your user has the right to get the same (or at least equivalent) information that you are working with, especially when its the users money!

NobbZ

NobbZ

There are enough, just take 0.3, you can not represent that value as float32, the same is probably true for float64, but you can at least have a closer approximation.

Play around with the float converter, it shows you what is possible and what is not.

Also, just as an exercise. Try to find n and m: 0.3 = m / (2 ** n)

Even though that is not the real representation, it will give you an estimate what the problem is.

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Sure, here’s a concrete example:

Suppose you have a service where people want to send you numbers, and you’re going to do some kind of processing with those numbers, and then send back a result. Suppose it’s super simple, like a math test for kids where they’re asked to round a number.

The task is: Round “2.675” to the nearest hundredths place.

You take that value, and parse it to a float:

iex(7)> {value, _} = Float.parse("2.675")
{2.675, ""}

Yay! that looks right!

iex(8)> value |> Float.round(2)          
2.67

Oh no…

This happens because it isn’t actually 2.675, it’s 2.67499999999999982236431605997495353221893310546875 and Elixir is nice and displays something more friendly.

Yes, if you care about precision at all. To be clear, plenty of times you don’t care about precision. Maybe you’re doing geolocation stuff where precision is carried as a separate term anyway, maybe you’re doing something in a GPU with floating point math. But if people want you to treat the number as it is written, you can’t convert it to a float, at all.

Last Post!

wojtekmach

wojtekmach

Hex Core Team

Thanks for writing down what worked for you, always appreciated!

My only suggestion would be to add the following check to catch values that’d be considered invalid:

+ if Decimal.inf?(value) or Decimal.nan?(value) do
+   raise "cannot encode #{inspect(value)} to JSON"
+ end

  Decimal.to_string(value, :normal)

Where Next?

Popular in Questions Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New

Other popular topics Top

baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 40165 209
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
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New

We're in Beta

About us Mission Statement