Reputation: 2674
I need a function that takes a Decimal (it’s money, so two decimal places) and rounds up to the nearest quarter. I’m trying to avoid converting to floats and staying within the Decimal world. (I've looked at the Money
library also and don't see a rounding function that does what I need.
This function works, but it is hideous. The decimal library only natively supports rounding to the whole or half, and I can’t slip values like :lt and :gt into Enum.member? because they are not enumerable, so I used separate conditions for :lt and :gt.
def round_up_to_nearest_quarter(preroundedamount) do
alias Decimal, as: D
base = D.round(preroundedamount, 0, :floor)
frac = D.sub(preroundedamount, base)
newfrac =
cond do
D.cmp(frac, 0) == :eq ->
D.new("0.0")
D.cmp(frac, D.new("0.25")) == :lt ->
D.new("0.25")
D.cmp(frac, D.new("0.25")) == :eq ->
D.new("0.25")
D.cmp(frac, D.new("0.5")) == :lt ->
D.new("0.5")
D.cmp(frac, D.new("0.5")) == :eq ->
D.new("0.5")
D.cmp(frac, D.new("0.75")) == :lt ->
D.new("0.75")
D.cmp(frac, D.new("0.75")) == :eq ->
D.new("0.75")
D.cmp(frac, D.new("1.0")) == :lt ->
D.new("1.0")
D.cmp(frac, D.new("1.0")) == :eq ->
D.new("1.0")
true ->
D.new("0.0")
end
D.add(base, newfrac)
end
What is the most Elixir-ian** way to do this?
**Also, what is the adjective form of “Elixir”? Looking for something like “Pythonic”.
Upvotes: 1
Views: 301
Reputation: 222168
To round up to the nearest multiple of 0.25, you can multiply the number by 4, do a normal round up, and then divide it by 4:
rounded = n |> Decimal.mult(4) |> Decimal.round(0, :up) |> Decimal.div(4)
Test:
for i <- 1..25 do
# 0.1, 0.2, ..., 2.5
n = Decimal.new(i) |> Decimal.div(Decimal.new(10))
rounded = n |> Decimal.mult(4) |> Decimal.round(0, :up) |> Decimal.div(4)
IO.inspect {Decimal.to_string(n), Decimal.to_string(rounded)}
end
Output:
{"0.1", "0.25"}
{"0.2", "0.25"}
{"0.3", "0.5"}
{"0.4", "0.5"}
{"0.5", "0.5"}
{"0.6", "0.75"}
{"0.7", "0.75"}
{"0.8", "1"}
{"0.9", "1"}
{"1", "1"}
{"1.1", "1.25"}
{"1.2", "1.25"}
{"1.3", "1.5"}
{"1.4", "1.5"}
{"1.5", "1.5"}
{"1.6", "1.75"}
{"1.7", "1.75"}
{"1.8", "2"}
{"1.9", "2"}
{"2", "2"}
{"2.1", "2.25"}
{"2.2", "2.25"}
{"2.3", "2.5"}
{"2.4", "2.5"}
{"2.5", "2.5"}
Upvotes: 3