From d3ef0bb7b54b87a1649ccb75fdb410bc2b807d5f Mon Sep 17 00:00:00 2001 From: Daniel Kukula Date: Wed, 8 Jan 2025 22:21:15 +0100 Subject: [PATCH 1/2] dk_optimize_float_parsing --- lib/elixir/lib/float.ex | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/lib/elixir/lib/float.ex b/lib/elixir/lib/float.ex index 07313e45d31..295c20274ee 100644 --- a/lib/elixir/lib/float.ex +++ b/lib/elixir/lib/float.ex @@ -21,7 +21,7 @@ defmodule Float do and arithmetic due to the fact most decimal fractions cannot be represented by a floating-point binary and most operations are not exact, but operate on approximations. Those issues are not specific - to Elixir, they are a property of floating point representation itself. + to Elixir,mthey are a property of floating point representation itself. For example, the numbers 0.1 and 0.01 are two of them, what means the result of squaring 0.1 does not give 0.01 neither the closest representable. Here is @@ -164,40 +164,50 @@ defmodule Float do end defp parse_unsigned(<>) when digit in ?0..?9, - do: parse_unsigned(rest, false, false, <>) + do: parse_unsigned(rest, false, false, [digit]) defp parse_unsigned(binary) when is_binary(binary), do: :error defp parse_unsigned(<>, dot?, e?, acc) when digit in ?0..?9, - do: parse_unsigned(rest, dot?, e?, <>) + do: parse_unsigned(rest, dot?, e?, [digit | acc]) defp parse_unsigned(<>, false, false, acc) when digit in ?0..?9, - do: parse_unsigned(rest, true, false, <>) + do: parse_unsigned(rest, true, false, [digit, ?. | acc]) defp parse_unsigned(<>, dot?, false, acc) when exp_marker in ~c"eE" and digit in ?0..?9, - do: parse_unsigned(rest, true, true, <>) + do: parse_unsigned(rest, true, true, [digit, ?e | add_dot(acc, dot?)]) defp parse_unsigned(<>, dot?, false, acc) when exp_marker in ~c"eE" and sign in ~c"-+" and digit in ?0..?9, - do: parse_unsigned(rest, true, true, <>) + do: parse_unsigned(rest, true, true, [digit, sign, ?e | add_dot(acc, dot?)]) # When floats are expressed in scientific notation, :erlang.binary_to_float/1 can raise an # ArgumentError if the e exponent is too big. For example, "1.0e400". Because of this, we # rescue the ArgumentError here and return an error. defp parse_unsigned(rest, dot?, true = _e?, acc) do - :erlang.binary_to_float(add_dot(acc, dot?)) + acc + |> add_dot(dot?) + |> :lists.reverse() + |> :erlang.list_to_float() rescue ArgumentError -> :error else float -> {float, rest} end - defp parse_unsigned(rest, dot?, false = _e?, acc), - do: {:erlang.binary_to_float(add_dot(acc, dot?)), rest} + defp parse_unsigned(rest, dot?, false = _e?, acc) do + float = + acc + |> add_dot(dot?) + |> :lists.reverse() + |> :erlang.list_to_float() + + {float, rest} + end defp add_dot(acc, true), do: acc - defp add_dot(acc, false), do: acc <> ".0" + defp add_dot(acc, false), do: [?0, ?. | acc] @doc """ Rounds a float to the largest float less than or equal to `number`. From 587625ee94ebff8cc9af2e897c8bf82d535764bb Mon Sep 17 00:00:00 2001 From: Daniel Kukula Date: Wed, 8 Jan 2025 22:33:08 +0100 Subject: [PATCH 2/2] typo --- lib/elixir/lib/float.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/elixir/lib/float.ex b/lib/elixir/lib/float.ex index 295c20274ee..c42907f40db 100644 --- a/lib/elixir/lib/float.ex +++ b/lib/elixir/lib/float.ex @@ -21,7 +21,7 @@ defmodule Float do and arithmetic due to the fact most decimal fractions cannot be represented by a floating-point binary and most operations are not exact, but operate on approximations. Those issues are not specific - to Elixir,mthey are a property of floating point representation itself. + to Elixir, they are a property of floating point representation itself. For example, the numbers 0.1 and 0.01 are two of them, what means the result of squaring 0.1 does not give 0.01 neither the closest representable. Here is