lib/strconv: f64tos Ryū shortest float→string (#106 fold-5a)
Graduate f64tos from the lossy fixed-point placeholder to Ryū shortest- round-trippable (ftos.ha:432 + ftos_ryu.ha). f64tos(n:f64) str, G-format (void/NONE) — the faithful documented subset (full parametric fftosf is dead code for G/void/NONE → deferred #64). Ryū core decomposed: struct- RETURN + scalar params (Hare's r128 idiom; avoids tuple-ABI #163-166). f64 powers tables [15][2]/[13][2]u64 (2D #156). Zero float literals. Both E+F encode paths reachable+tested, no dead code. Graduation (lib-note "don't keep both"): old lossy f64tos deleted; fmt fprintf_f64_huge "huge"→"9.5e18" (improvement). 5 value-faithful filed- bug dodges (byte-id, documented): #167/#169/#170/#43/#144. Test 908. Make test 186/186 incl 990-997 byte-id + combined_ww_fresh. Drew's strconv 5-fold plan — primary completion (f64tos). f32tos coda #67 (behind #143); parametric ftosf #64.
This commit is contained in:
93
lib/strconv/test/ftostest.ww
Normal file
93
lib/strconv/test/ftostest.ww
Normal file
@@ -0,0 +1,93 @@
|
||||
// ftostest — exercises lib/strconv/ftos.ww (Hare ftos.ha / ftos_ryu.ha
|
||||
// Ryū port). Run with `out/bin/ww run lib/strconv/test/ftostest.ww`.
|
||||
// Same signalled-then-os.exit(signalled+10) pattern as stoftest/
|
||||
// decimaltest: a non-zero exit names the failing @test (1..N → 11..N+10).
|
||||
//
|
||||
// Ports ref/hare/strconv/+test/ftos_test.ha's ffmt::G / prec=void /
|
||||
// fflags::NONE rows (the f64tos cases) verbatim — these are exactly
|
||||
// strconv.f64tos's output. encode_f_dec is covered by 13.37/1100/0.011/…
|
||||
// and encode_e_dec by 1e4/1.1e4/1e-3/1.1e-3/1e-4. nan/±infinity via
|
||||
// math.f64frombits of the IEEE bit patterns (ww math has no f64 NAN/INF
|
||||
// const — see math/floats.ww).
|
||||
//
|
||||
// f32tos is NOT exercised here: it is deferred to fold-5b (task #67),
|
||||
// gated on the #143 f32-arg-push cs≠ww cgen fix.
|
||||
//
|
||||
// Lives in lib/strconv/test/ so `import strconv` resolves to the
|
||||
// DIRECTORY (full package), not the strconv.ww FILE — same rationale as
|
||||
// stoftest/decimaltest.
|
||||
|
||||
package strconv;
|
||||
|
||||
import strconv;
|
||||
import os;
|
||||
import math;
|
||||
|
||||
let signalled: i32 = 0;
|
||||
fn fail() void = { os.exit(signalled + 10); };
|
||||
|
||||
fn streq(a: str, b: str) bool = {
|
||||
if (a.len != b.len) { return false; };
|
||||
let k: i32 = 0i32;
|
||||
for (k < a.len) {
|
||||
if (a[k] != b[k]) { return false; };
|
||||
k += 1i32;
|
||||
};
|
||||
return true;
|
||||
};
|
||||
|
||||
fn chk(n: f64, want: str) bool = {
|
||||
return streq(f64tos(n), want);
|
||||
};
|
||||
|
||||
// ftos_test.ha:57-64 (G/void/NONE-equivalent) — fixed-point renders.
|
||||
@test fn f64tos_fixed() void = {
|
||||
if (!chk(13.37, "13.37")) { fail(); };
|
||||
if (!chk(12345.0, "12345")) { fail(); };
|
||||
if (!chk(1100.0, "1100")) { fail(); };
|
||||
if (!chk(100.0, "100")) { fail(); };
|
||||
if (!chk(10.0, "10")) { fail(); };
|
||||
if (!chk(1.0, "1")) { fail(); };
|
||||
if (!chk(0.3, "0.3")) { fail(); };
|
||||
if (!chk(0.1, "0.1")) { fail(); };
|
||||
if (!chk(0.01, "0.01")) { fail(); };
|
||||
if (!chk(0.011, "0.011")) { fail(); };
|
||||
if (!chk(1.414, "1.414")) { fail(); };
|
||||
if (!chk(-6345.972, "-6345.972")) { fail(); };
|
||||
};
|
||||
|
||||
// ftos_test.ha:78-90 — scientific renders (the shortest-G E-dispatch).
|
||||
@test fn f64tos_scientific() void = {
|
||||
if (!chk(10000.0, "1e4")) { fail(); };
|
||||
if (!chk(11000.0, "1.1e4")) { fail(); };
|
||||
if (!chk(1000.0, "1e3")) { fail(); };
|
||||
if (!chk(0.001, "1e-3")) { fail(); };
|
||||
if (!chk(0.0011, "1.1e-3")) { fail(); };
|
||||
if (!chk(0.0001, "1e-4")) { fail(); };
|
||||
// dp=-2 < -1 → G dispatches to E (ftos_test.ha:62 is the ffmt::F row;
|
||||
// shortest-G of 0.0031415 is scientific).
|
||||
if (!chk(0.0031415, "3.1415e-3")) { fail(); };
|
||||
};
|
||||
|
||||
// ftos_test.ha:12/16/27 — zero, ±infinity, nan.
|
||||
@test fn f64tos_special() void = {
|
||||
if (!chk(0.0, "0")) { fail(); };
|
||||
// sign bit via (1u64 << 63), not the 0x8000000000000000 literal:
|
||||
// wwstage mis-emits the I64_MIN-magnitude literal (#144 family).
|
||||
let negzero: f64 = math.f64frombits(1u64 << 63u64);
|
||||
if (!chk(negzero, "-0")) { fail(); };
|
||||
let inf: f64 = math.f64frombits(0x7FF0000000000000u64);
|
||||
if (!chk(inf, "infinity")) { fail(); };
|
||||
let ninf: f64 = math.f64frombits(0xFFF0000000000000u64);
|
||||
if (!chk(ninf, "-infinity")) { fail(); };
|
||||
let nan: f64 = math.f64frombits(0x7FF8000000000000u64);
|
||||
if (!chk(nan, "nan")) { fail(); };
|
||||
};
|
||||
|
||||
export fn main() i32 = {
|
||||
signalled = 1; f64tos_fixed();
|
||||
signalled = 2; f64tos_scientific();
|
||||
signalled = 3; f64tos_special();
|
||||
os.exit(0);
|
||||
return 0;
|
||||
};
|
||||
Reference in New Issue
Block a user