Expand description
Float text, byte-identical to Rust’s formatting and faster.
A tile encodes an f64 hole as format!("{f:?}") when the hole has
no format and as format!("{f:.N}") under a .N precision (SRD 114
§7.2). Those bytes are the tile’s contract on every engine, so a
faster writer is only admissible if it produces the same bytes for
every value. This module is that writer, and
tests/float_text.rs is the proof: a differential over edge values,
arithmetic series, and a million seeded bit patterns, for the
shortest form and every precision 0 through 9.
Shortest form (write_shortest). Rust’s Debug for f64
prints the shortest round-trip digits, as a decimal with at least
one fractional digit (100.0, 0.1, -0.0) when the magnitude is
in [1e-4, 1e16) and otherwise in exponent form (1e16,
1.5e-7). The ryu crate produces the same shortest digits and,
for every class but one, the same layout; the exception is
[1e-5, 1e-4), which ryu lays out as 0.00005 and Rust as 5e-5.
The writer takes ryu’s text and re-lays out that one class from
ryu’s digits. The digits themselves agree except on a tie: a value
whose exact decimal expansion is one digit longer than its shortest
form and ends in 5 (2231889947293916.25, whose shortest forms
…916.2 and …916.3 both round-trip), where ryu rounds to the
even digit and Rust rounds up. The writer detects a tie exactly from
the float’s odd mantissa and exponent and falls back to format!
for it, so the proof’s random sweep is what establishes that no
other class differs.
Fixed precision (write_fixed). format!("{f:.N}") rounds
the exact binary value to N fractional digits, half to even on the
exact decimal expansion. Rounding the shortest digits is not the
same operation (0.295 is below the tie in binary, so .2 gives
0.29, where rounding the text 0.295 half-even gives 0.30).
The writer decodes the float to m * 2^e and computes
round(m * 10^N * 2^e) in u128 arithmetic: for e < 0 the
quotient and remainder of a shift, compared against the half; for
e >= 0 a left shift with no rounding at all. That is exact
wherever m * 10^N * 2^max(e,0) fits in 128 bits, which covers
N <= 22 and magnitudes below about 2^(75 - 3.33 N) (1.6e29 at
N = 9); every other case falls back to format!, so the output is
Rust’s own where the fast path does not reach. A magnitude below the
fast path’s shift range is exactly zero at any supported precision
and is written as such without a fallback.
Functions§
- fixed_
is_ fast - Whether
write_fixedtakes the exact fast path forfatprec, or falls back toformat!. Exposed so the proof can report its fallback rate. - fixed_
string write_fixedinto a newString.- shortest_
is_ fast - Whether
write_shortesttakes the ryu path forf, or falls back toformat!on a tie. Exposed so the proof can report its fallback rate. - shortest_
string write_shortestinto a newString.- write_
fixed - Write
fexactly asformat!("{f:.prec$}")does. - write_
shortest - Write
fexactly asformat!("{f:?}")does.