Reputation: 2331
What is the most direct, & efficient way to do this in Elixir?
Starting number: 123.101
Ending number: 123.101000 # Adding 3 digits to the precision of a float.
Starting number: 123
Ending number: 123.000 # Adding 3 digits to the precision of an integer.
Starting number: 123.101
Ending number: 123.1 # removing precision
Starting number: 123.000
Ending number: 123 # removing precision
Upvotes: 27
Views: 19740
Reputation: 303
These answers are mostly odd. First, she didn't say anything about converting to a string. Second, there is certainly no need to jump into Erlang land!
In order:
Starting number: 123.101
Ending number: 123.101000 # Adding 3 digits to the precision of a float.
iex> 123.101 |> Decimal.from_float() |> Decimal.round(6)
#Decimal<123.101000>
Starting number: 123
Ending number: 123.000 # Adding 3 digits to the precision of an integer.
iex> 123 |> Decimal.from_float() |> Decimal.round(3)
#Decimal<123.000>
Starting number: 123.101
Ending number: 123.1 # removing precision
iex> 123.101 |> Decimal.from_float() |> Decimal.round(1)
#Decimal<123.1>
Starting number: "123.000" # must be a string as 123.000 == 123.0
Ending number: 123 # removing precision
iex> "123.000" |> Decimal.new() |> Decimal.round(0)
#Decimal<123>
Once you have a number in Decimal
, you can do what you want, e.g. convert to a float, convert to a string, etc.
iex> 123.101 |> Decimal.new() |> Decimal.round(6) |> Decimal.to_string()
"123.101000"
iex> 123.101 |> Decimal.new() |> Decimal.round(6) |> Decimal.to_float()
123.101
iex> 123.101 |> Decimal.new() |> Decimal.round(0) |> Decimal.to_integer()
123
As an aside, I recommend working only in Decimal
until you've finished any data manipulation, e.g. using Decimal.mult(num1, num2)
, Decimal.div(num1, num2)
, etc. Decimal
rocks!
Upvotes: 10
Reputation: 5804
Just want to supply a alternative to Dogbert's excellent answer.
It is also possible to use :erlang.float_to_binary/2
ex.
iex(5)> :erlang.float_to_binary(123.101, [decimals: 6])
"123.101000"
iex(6)> :erlang.float_to_binary(123.0, [decimals: 3])
"123.000"
iex(7)> :erlang.float_to_binary(123.101, [decimals: 1])
"123.1"
iex(8)> :erlang.float_to_binary(123.000, [decimals: 0])
"123"
Upvotes: 42
Reputation: 121000
Just out of curiosity, that’s how I would implement in in pure Elixir:
defmodule NumFmt do
def format(value, pos, round? \\ true)
def format(value, pos, _) when is_integer(value),
do: format(Integer.to_string(value), pos)
def format(value, pos, round?) when is_float(value),
do: format(Float
|> apply((if round?, do: :round, else: :floor), [value, pos])
|> Float.to_string, pos)
def format(value, 0, _) when is_binary(value),
do: with [i | _] <- String.split(value, "."), do: i
def format(value, pos, round?) when is_binary(value) do
case String.split(value, ".") do
[i] -> format(i <> ".0", pos, round?)
[i, f] -> [i, f
|> String.pad_trailing(pos, "0")
|> String.slice(0..pos - 1)] |> Enum.join(".")
end
end
end
IO.inspect NumFmt.format(123.101, 6), label: "123.101000"
#⇒123.101000: "123.101000"
IO.inspect NumFmt.format(123, 3), label: "123.000"
#⇒ 123.000: "123.000"
IO.inspect NumFmt.format(123.101, 1), label: "123.1"
#⇒ 123.1: "123.1"
IO.inspect NumFmt.format(123.000, 0), label: "123"
#⇒ 123: "123"
Upvotes: 2
Reputation: 222060
There isn't anything like this in Elixir's standard library as far as I know, but you can use :io_lib.format/2
from Erlang to print a float with specific number of digits after the dot:
iex(1)> :io_lib.format("~.3f", [123.101])
['123.101']
iex(2)> :io_lib.format("~.6f", [123.101])
['123.101000']
iex(3)> :io_lib.format("~.3f", [123.0])
['123.000']
iex(4)> :io_lib.format("~.6f", [123.0])
['123.000000']
The returned value is an iolist
, which can be converted to a binary using IO.iodata_to_binary/1
if required (many functions that take a binary can accept an iolist
directly as well, e.g. IO.puts/1
):
iex(5)> :io_lib.format("~.6f", [123.0]) |> IO.iodata_to_binary
"123.000000"
~.0f
doesn't work but for that you can simply call trunc/1
:
iex(6)> trunc(123.123)
123
Upvotes: 7
Reputation: 4885
I've used the decimal package for this previously
iex(6)> 123 |> Decimal.new() |> Decimal.round(3) |> Decimal.to_string()
"123.000"
In my case the data was already in Decimal format after being queried from the database.
Upvotes: 2