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.

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:

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.

https://www.h-schmidt.net/FloatConverter/IEEE754.html

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.

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Yeah if people care about precision, they should avoid floats at all layers and use decimal libraries at all layers.

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

vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
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
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
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
gonzofish
I’m currently trying to understand how to join three tables using Ecto. All the examples I’ve seen use 2, so maybe I’m just missing somet...
New
kostonstyle
Hi all I want to have a unix time, from the current time plus 1 hour. DateTime.now + 1 hour How to get it in elixir? Thanks
New
chewm
Hi guys, nice to meet you to the whole forum, I’m new here, I’m trying to configure visual studio code for elixir, right now the intellis...
New
jc00ke
Expanding on this topic: https://forum.elixirforum.net/t/map-typespec-question/19217 Let’s say I have a map with required and optional k...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New

Other popular topics Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
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
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
Nvim
Elixir appears to be a superior language to Python. I don’t see any advantage of Python over Elixir. Are there any?
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New

We're in Beta

About us Mission Statement