我有这个代码和测试:
def order_quantity(:sell, free_quantity, lot_step_size, quantity_precision) do
{q, _} = :erlang.float_to_binary(Float.floor(free_quantity / lot_step_size) * lot_step_size, decimals: quantity_precision) |> Float.parse()
q
end
assert order_quantity(:sell, 0.01977578, 0.00010000, 8) == 0.0197
assert order_quantity(:sell, 0.290709, 0.00100000, 8) == 0.29000000
assert order_quantity(:sell, 111.88800000, 0.01000000, 8) == 111.88
但我对此并不满意——有没有更像 Elixir 的方法来完成相同的计算?
Float.floor/2
是你的朋友。
iex|1▸ Float.floor 0.01977578, 4
0.0197
iex|2▸ Float.floor 0.290709, 3
0.29
iex|3▸ Float.floor 111.88800000, 2
111.88
此外,您可能最好重新考虑如何通过
free_quantity
。将其作为整数传递可能更有意义,而不是不一定精确浮点数。
如果你关心精度,你应该使用
:decimal
库。 https://hexdocs.pm/decimal/Decimal.html
有了这个你可以简单地做:
iex> Decimal.round("0.01977578", 4, :down)
#Decimal<0.0197>
第一个参数是浮点数或字符串,第二个参数是小数位数,第三个参数是舍入“模式”。
您的主要问题是如何从
lot_step_size
浮点数中获取小数位数(整数)。
你可以创建一个函数来计算
places
从任何给定的手步长,但如果你知道这些只到,比如说,小数点后 8 位,那么你可以为每个写一个更有效(更快)的“模式”,如下所示:
def places(0.00000001), do: 8
def places(0.0000001), do: 7
def places(0.000001), do: 6
def places(0.00001), do: 5
def places(0.0001), do: 4
def places(0.001), do: 3
def places(0.01), do: 2
def places(0.1), do: 1
def order_quantity(:sell, free_quantity, lot_step_size) do
free_quantity
|> to_string()
|> Decimal.round(places(lot_step_size), :down)
|> Decimal.to_float()
end
请注意,我在完成后转换回浮点数,但你最好在所有地方使用 Decimal 并避免浮点数。