Skip to content

perf(stdlib): use io_lib.format for string.format float conversion #311

@davydog187

Description

@davydog187

Context

string.format with many specifiers is 1.85× slower than luerl (n=1000:
7.42ms vs 4.00ms in benchmarks/string_format.exs). The dominant per-call
cost is format_spec_float/2 at lib/lua/vm/stdlib/string.ex:454-501, which
calls :erlang.float_to_binary and then post-processes through
String.split, String.pad_trailing, and string interpolation in
expand_float/2.

Luerl (deps/luerl/src/luerl_lib_string_format.erl:248-250) delegates the
entire conversion to io_lib:format/2, handling precision, sign, and
rounding in a single native Erlang call.

Change

lib/lua/vm/stdlib/string.ex:454-501 (format_spec_float/2) and likely
format_spec_scientific/3 at line 503.

  • Replace
    :erlang.float_to_binary([{:decimals, P}, :compact]) + expand_float
    with a direct :io_lib.format(~c\"%.*f\", [precision, val]).
  • Apply the same pattern for %e and %g.
  • Delete expand_float/2.

Compatibility check (required)

Confirm rounding matches C Lua across:

  • test/lua/vm/stdlib/string_test.exs (all existing format cases)
  • Lua 5.3 suite tests touching format/literals

Add unit tests around: precision-0 rounding (sign matters at boundaries),
large precision, inf/nan formatting.

Verification

  • mix test (full suite)
  • mix run benchmarks/string_format.exs

Expected

Closes the remainder of the spec-heavy gap. May flip us ahead of luerl on
many specs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind:perfPerformance change

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions