Format float precision and formatting fractions

phoenix
phoenix_html

#1

I am displaying float values (ratings, price, etc.) and fractions in html.eex templates, and want to format the precision across different views. I don’t want to repeatedly format each instance of a variable in each template.

I would appreciate if someone would point me in the right direction for the following:

  1. How would I format floats across views?
  2. How would I format floats across an attribute? e.g., set a variable attribute or flag for :rating and :price, respectively, where :rating has Float.round(3) and :price has Float.round(2)?
  3. What’s the correct way to input and output fractional values? Example: input height of 6'2" and display as 6 feat 2 inches or input length of 1' 3/8" and display as 1.375 (or vice versa: input 1.375 and output 1' 3/8")

thank you


#2

I don’t have a complete answer for you, but a couple of pointers that may or may not help:

  1. For formatting money there is a lib ex_money that would help. I am the author. Hopefully you aren’t really using floats though, its not a good practise.
iex> Money.to_string Money.new(:USD, 100)
$100.00
  1. For formatting units like lengths or volumes, … I also author a package called ex_cldr_units although it doesn’t do “feet and inches”. You would need to format feet and inches separately.
iex> MyApp.Cldr.Unit.to_string 6, unit: :foot
6 feet
iex> MyApp.Cldr.Unit.to_string 1, unit: :foot
6 foot

I’ve had the idea of doing unit reductions during formatting (miles -> yards -> feet -> inches style) and fractional formats (3/8) but they aren’t done. Happy to take feedback from you and others if this is useful.


#3

Would the answer to question 1 and 2 be handled via protocols?

Also, those libraries look great, thank you for authoring them.

(tautology warning ahead :grinning:) … Yes, unit reduction formatting with fractional formats would be ideal for user facing applications with fractional measurements, with the same example as before: input 1.375 and output 1' 3/8"


#4

I have just release ex_cldr_units version 2.1.0 that provides a unit reduction mechanism. Using your initial example:

iex> height = Cldr.Unit.new(:foot, 6.3)
#Unit<:foot, 6.3>

# Cldr.Unit.decompose creates a list of subunits from the specification provided
c = Cldr.Unit.decompose height, [:foot, :inch]
[#Unit<:foot, 6.0>, #Unit<:inch, 4.0>]

# This can then be output as a localised string which
# leverages the list localised list formatting in [ex_cldr_lists](https://hex.pm/packages/ex_cldr_lists)
iex> Cldr.Unit.to_string c, MyApp.Cldr
"6 feet and 4 inches"

# Cldr.List.to_string/2 options can be provided
iex> Cldr.Unit.to_string c, MyApp.Cldr, list_options: [format: :unit_short]
"6 feet, 4 inches"

# And of course full localisation is supported
iex> Cldr.Unit.to_string c, MyApp.Cldr, locale: "fr"
"6 pieds et 4 pouces"

I’m still considering fractional output.


#5

As for fractions, you could consider ratio shameless plug which allows to convert 1.375 to 1 3/4 for you. It won’t do the printing part for you though, but you’re able to easily read out the ‘1’ , ‘3’ and ‘4’ from the resulting rational number for your own printing routine :slight_smile:.


#6

Thanks @qqwy, I was cruising Hex looking for that, i knew you’d written one - i thought it was called rational.


#7

Thanks for library update @kip, and library mention @Qqwy. That solves #3 nicely. However, for #1 and #2, I have not found an idiomatic solution to formatting data types selectively across views. I’ve opted for a non-ideal solution of piping the input to a formatter function directly from elixir expressions inside templates.


#8

My pedantic background brain thread just asked for attention. I suspect that’s a typographical error and not actually what the library produces. 1.375 is 1 3/8