Skip to content

Commit 194ecfd

Browse files
authored
Optimize Float.parse/1 (#14159)
1 parent ef1450d commit 194ecfd

File tree

1 file changed

+19
-9
lines changed

1 file changed

+19
-9
lines changed

lib/elixir/lib/float.ex

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -164,40 +164,50 @@ defmodule Float do
164164
end
165165

166166
defp parse_unsigned(<<digit, rest::binary>>) when digit in ?0..?9,
167-
do: parse_unsigned(rest, false, false, <<digit>>)
167+
do: parse_unsigned(rest, false, false, [digit])
168168

169169
defp parse_unsigned(binary) when is_binary(binary), do: :error
170170

171171
defp parse_unsigned(<<digit, rest::binary>>, dot?, e?, acc) when digit in ?0..?9,
172-
do: parse_unsigned(rest, dot?, e?, <<acc::binary, digit>>)
172+
do: parse_unsigned(rest, dot?, e?, [digit | acc])
173173

174174
defp parse_unsigned(<<?., digit, rest::binary>>, false, false, acc) when digit in ?0..?9,
175-
do: parse_unsigned(rest, true, false, <<acc::binary, ?., digit>>)
175+
do: parse_unsigned(rest, true, false, [digit, ?. | acc])
176176

177177
defp parse_unsigned(<<exp_marker, digit, rest::binary>>, dot?, false, acc)
178178
when exp_marker in ~c"eE" and digit in ?0..?9,
179-
do: parse_unsigned(rest, true, true, <<add_dot(acc, dot?)::binary, ?e, digit>>)
179+
do: parse_unsigned(rest, true, true, [digit, ?e | add_dot(acc, dot?)])
180180

181181
defp parse_unsigned(<<exp_marker, sign, digit, rest::binary>>, dot?, false, acc)
182182
when exp_marker in ~c"eE" and sign in ~c"-+" and digit in ?0..?9,
183-
do: parse_unsigned(rest, true, true, <<add_dot(acc, dot?)::binary, ?e, sign, digit>>)
183+
do: parse_unsigned(rest, true, true, [digit, sign, ?e | add_dot(acc, dot?)])
184184

185185
# When floats are expressed in scientific notation, :erlang.binary_to_float/1 can raise an
186186
# ArgumentError if the e exponent is too big. For example, "1.0e400". Because of this, we
187187
# rescue the ArgumentError here and return an error.
188188
defp parse_unsigned(rest, dot?, true = _e?, acc) do
189-
:erlang.binary_to_float(add_dot(acc, dot?))
189+
acc
190+
|> add_dot(dot?)
191+
|> :lists.reverse()
192+
|> :erlang.list_to_float()
190193
rescue
191194
ArgumentError -> :error
192195
else
193196
float -> {float, rest}
194197
end
195198

196-
defp parse_unsigned(rest, dot?, false = _e?, acc),
197-
do: {:erlang.binary_to_float(add_dot(acc, dot?)), rest}
199+
defp parse_unsigned(rest, dot?, false = _e?, acc) do
200+
float =
201+
acc
202+
|> add_dot(dot?)
203+
|> :lists.reverse()
204+
|> :erlang.list_to_float()
205+
206+
{float, rest}
207+
end
198208

199209
defp add_dot(acc, true), do: acc
200-
defp add_dot(acc, false), do: acc <> ".0"
210+
defp add_dot(acc, false), do: [?0, ?. | acc]
201211

202212
@doc """
203213
Rounds a float to the largest float less than or equal to `number`.

0 commit comments

Comments
 (0)