Skip to content

Commit d3ef0bb

Browse files
committed
dk_optimize_float_parsing
1 parent 38f460e commit d3ef0bb

File tree

1 file changed

+20
-10
lines changed

1 file changed

+20
-10
lines changed

lib/elixir/lib/float.ex

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ defmodule Float do
2121
and arithmetic due to the fact most decimal fractions cannot be
2222
represented by a floating-point binary and most operations are not exact,
2323
but operate on approximations. Those issues are not specific
24-
to Elixir, they are a property of floating point representation itself.
24+
to Elixir,mthey are a property of floating point representation itself.
2525
2626
For example, the numbers 0.1 and 0.01 are two of them, what means the result
2727
of squaring 0.1 does not give 0.01 neither the closest representable. Here is
@@ -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)