lib/strconv: stof.ha port — Eisel-Lemire string→float (#106 fold-4)

stof64/stof32 (f64|f32 | invalid | overflow) via Eisel-Lemire fast-path
(powers_of_ten[596][2]u64 + eisel_lemire 128-bit multiply) + decimal
slow-path fallback (decimal.ww, fold-3). 16 fns + faithful powers_of_ten
(byte-identical to Hare). u128 via pure-u64 64×64→128 (ftos_ryu.ha).
Consumes &math.f64info (γ-cleanup), tagged-float-return (PREREQ-2 #157),
2D double-index (PREREQ-1 #156).

13 documented spelling-divergences (rule-9, each cites stof.ha): #155
(po10 double-index + per-field struct-copy), #161 (compound-assign explicit
form), #144 (-0.0 via 1u64<<63), #158, #138, test-only #143/parsef64.
Test 909 (DEC+hex+NaN/Inf/invalid/overflow, bit-exact, cstage ww run).
Make test 185/185 incl 990-997 byte-id + combined_ww_fresh. Makefile:
stof.ww added to w6c_ww/wwdump_ww deps (freshness, fold-3 precedent).

Drew's strconv 5-fold plan 4/5. Followup #162 (wwstage lexer parsef64
1-ULP — could adopt stof64).
This commit is contained in:
2026-05-27 13:55:56 +09:00
parent 4a91bdc8db
commit 81796cd533
8 changed files with 6977 additions and 606 deletions

View File

@@ -113,7 +113,7 @@ $(BIN)/wwdump_ww: selfhost/cmd/wwdump/main.ww \
selfhost/cmd/wcc/cgen.ww selfhost/cmd/wcc/cgenexpr.ww \ selfhost/cmd/wcc/cgen.ww selfhost/cmd/wcc/cgenexpr.ww \
selfhost/cmd/wcc/cgenstmt.ww selfhost/cmd/wcc/cgenutil.ww \ selfhost/cmd/wcc/cgenstmt.ww selfhost/cmd/wcc/cgenutil.ww \
selfhost/cmd/wcc/cgendecl.ww \ selfhost/cmd/wcc/cgendecl.ww \
lib/os/os.ww lib/rt/malloc.ww lib/time/time.ww lib/strconv/strconv.ww lib/strconv/stof_data.ww lib/strconv/decimal.ww lib/strings/strings.ww lib/bytes/bytes.ww lib/encoding/utf8/utf8.ww lib/ascii/ascii.ww lib/io/io.ww lib/memio/memio.ww lib/fmt/fmt.ww \ lib/os/os.ww lib/rt/malloc.ww lib/time/time.ww lib/strconv/strconv.ww lib/strconv/stof_data.ww lib/strconv/decimal.ww lib/strconv/stof.ww lib/strings/strings.ww lib/bytes/bytes.ww lib/encoding/utf8/utf8.ww lib/ascii/ascii.ww lib/io/io.ww lib/memio/memio.ww lib/fmt/fmt.ww \
$(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \ $(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
$(LIB)/libwwrt.a | $(BIN) $(LIB)/libwwrt.a | $(BIN)
@mkdir -p $(BIN)/wwdump_ww.d @mkdir -p $(BIN)/wwdump_ww.d
@@ -135,7 +135,7 @@ $(BIN)/w6c_ww: selfhost/cmd/w6c/main.ww \
selfhost/cmd/wcc/cgen.ww selfhost/cmd/wcc/cgenexpr.ww \ selfhost/cmd/wcc/cgen.ww selfhost/cmd/wcc/cgenexpr.ww \
selfhost/cmd/wcc/cgenstmt.ww selfhost/cmd/wcc/cgenutil.ww \ selfhost/cmd/wcc/cgenstmt.ww selfhost/cmd/wcc/cgenutil.ww \
selfhost/cmd/wcc/cgendecl.ww \ selfhost/cmd/wcc/cgendecl.ww \
lib/os/os.ww lib/rt/malloc.ww lib/time/time.ww lib/strconv/strconv.ww lib/strconv/stof_data.ww lib/strconv/decimal.ww lib/strings/strings.ww lib/bytes/bytes.ww lib/encoding/utf8/utf8.ww lib/ascii/ascii.ww lib/io/io.ww lib/memio/memio.ww lib/fmt/fmt.ww \ lib/os/os.ww lib/rt/malloc.ww lib/time/time.ww lib/strconv/strconv.ww lib/strconv/stof_data.ww lib/strconv/decimal.ww lib/strconv/stof.ww lib/strings/strings.ww lib/bytes/bytes.ww lib/encoding/utf8/utf8.ww lib/ascii/ascii.ww lib/io/io.ww lib/memio/memio.ww lib/fmt/fmt.ww \
$(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \ $(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
$(LIB)/libwwrt.a | $(BIN) $(LIB)/libwwrt.a | $(BIN)
@mkdir -p $(BIN)/w6c_ww.d @mkdir -p $(BIN)/w6c_ww.d
@@ -322,7 +322,7 @@ TESTS = $(BIN)/test_smoke $(BIN)/test_lex $(BIN)/test_parse $(BIN)/test_check \
$(BIN)/test_intdiv_signed \ $(BIN)/test_intdiv_signed \
$(BIN)/test_strings_run \ $(BIN)/test_strings_run \
$(BIN)/test_hex_run $(BIN)/test_utf8_run $(BIN)/test_bytes_run \ $(BIN)/test_hex_run $(BIN)/test_utf8_run $(BIN)/test_bytes_run \
$(BIN)/test_decimal_run \ $(BIN)/test_decimal_run $(BIN)/test_stof_run \
$(BIN)/test_memio_run $(BIN)/test_temp_run $(BIN)/test_getopt_run \ $(BIN)/test_memio_run $(BIN)/test_temp_run $(BIN)/test_getopt_run \
$(BIN)/test_base32_run $(BIN)/test_base64_run \ $(BIN)/test_base32_run $(BIN)/test_base64_run \
$(BIN)/test_adler32_run $(BIN)/test_crc16_run \ $(BIN)/test_adler32_run $(BIN)/test_crc16_run \
@@ -1046,6 +1046,10 @@ $(BIN)/test_decimal_run: test/wcc/922_decimal_run.c $(BIN)/ww $(BIN)/w6c \
$(BIN)/w6a $(BIN)/w6l $(LIB)/libwwrt.a | $(BIN) $(BIN)/w6a $(BIN)/w6l $(LIB)/libwwrt.a | $(BIN)
$(CC) $(CFLAGS) -o $@ $< $(CC) $(CFLAGS) -o $@ $<
$(BIN)/test_stof_run: test/wcc/909_stof_run.c $(BIN)/ww $(BIN)/w6c \
$(BIN)/w6a $(BIN)/w6l $(LIB)/libwwrt.a | $(BIN)
$(CC) $(CFLAGS) -o $@ $<
$(BIN)/test_strings_run: test/wcc/966_strings_run.c $(BIN)/ww $(BIN)/w6c \ $(BIN)/test_strings_run: test/wcc/966_strings_run.c $(BIN)/ww $(BIN)/w6c \
$(BIN)/w6a $(BIN)/w6l $(LIB)/libwwrt.a | $(BIN) $(BIN)/w6a $(BIN)/w6l $(LIB)/libwwrt.a | $(BIN)
$(CC) $(CFLAGS) -o $@ $< $(CC) $(CFLAGS) -o $@ $<

700
lib/strconv/stof.ww Normal file
View File

@@ -0,0 +1,700 @@
// strconv — string-to-float. Mirrors ref/hare/strconv/stof.ha
// (Hare in turn adapts Go): Eisel-Lemire fast path [1] with the
// Simple-Decimal-Conversion slow path [2] (decimal.ww) as fallback.
// [1]: https://nigeltao.github.io/blog/2020/eisel-lemire.html
// [2]: https://nigeltao.github.io/blog/2020/parse-number-f64-simple.html
//
// The Eisel-Lemire fast path (`eisel_lemire` + the `powers_of_ten`
// table in stof_data.ww + the three call sites: floatbits's d.nd<=19
// block, stof64/stof32's !truncated block) is a pure speed
// optimisation — it returns the same correctly-rounded value the
// decimal slow path (decimal_parse → floatbits) computes, or void to
// defer. Its prereqs landed: the 2D `[596][2]u64` static-init +
// double-index read (#156) and the tagged float-variant return-pack
// (#157, which the public `(f64|invalid|overflow)` return needs).
//
// Spelling divergences from Hare (mechanical, ww parser/cgen shape):
// - str scan index rides `i32` (ww `str.len: i32` + `invalid = !i32`
// payload), not Hare's `size`/`len(s)`. lib CLAUDE.md str-index note.
// - char literals kept faithful (`buf[i] == '.'`, `c - '0'`); probed
// byte-id + value-correct both stages.
// - Hare `?` error-propagation → nested statement-`match` with all-
// return arms + a `case void => void` continuation. ww's `?`
// lowering and a bound `match`-expression with mixed yield/return
// arms both diverge cs≠ww (the latter wwstage-checker-rejected);
// strconv.ww's stoi32 set the explicit-match precedent.
// - Hare `for (cond; afterthought)` 2-clause + `continue` → ww
// 2-clause `for (cond)` with the afterthought inlined at body end
// AND before each `continue` (ww has no empty-init 3-clause
// `for (; c; p)`; #138 post-skip is dodged since 2-clause has no
// post). decimal.ww set the inline-afterthought precedent.
// - Hare `if`/`switch`-expression yield → explicit if-statements +
// pre-bound scalar locals (ww has no expression-bodied if).
// - Hare fn-pointer-in-tuple + `switch yield` selecting the digit
// predicate in fast_parse → a `base==HEX` bool + an `isdigitbase`
// helper that branches to ascii.isdigit/isxdigit (no fn-ptr, no
// tuple, no switch).
// - struct-param field MUTATION (hex_to_bits mutates its by-value
// `p`) → copy p's fields to scalar locals at entry; ww miscompiles
// + diverges on writing a by-value struct param's fields (filed).
// - default arg dropped: Hare `b: base = base::DEC` → callers pass
// base explicitly (no lib fn ships a default arg; strconv.ww
// stoi64 precedent). The base param is normalised through a local
// `bb` (param reassignment avoided).
// - `math::NAN`/`math::INF` (f32) absent in ww math → materialised
// via f32frombits of the IEEE-754 f32 bit patterns (same honest
// construction as math/floats.ww's NAN_BITS/INF_BITS).
// - narrowing int→i32 assignments carry explicit casts (ww `int` is
// an 8B machine word; project_int_machine_word_derived_limits).
// - `r128`/`u128mul` live here (fold-4 is first consumer); fold-5
// ftos (Ryū) shares them in-package.
package strconv;
import ascii;
import math;
import os;
import strings;
// ref/hare/strconv/ftos_ryu.ha:12. 64×64→128 result halves.
type r128 = struct {
hi: u64,
lo: u64,
};
// ref/hare/strconv/ftos_ryu.ha:18. 64×64→128 via 32-bit decomposition
// (Hare's own "TODO: use 128-bit integers when implemented" — ww has
// no u128; the decomposition is the portable shape both stages agree
// on). Comma let-bindings split per decimal.ww divergence.
fn u128mul(a: u64, b: u64) r128 = {
let a0: u64 = (a: u32): u64;
let a1: u64 = a >> 32u64;
let b0: u64 = (b: u32): u64;
let b1: u64 = b >> 32u64;
let p00: u64 = a0 * b0;
let p01: u64 = a0 * b1;
let p10: u64 = a1 * b0;
let p11: u64 = a1 * b1;
let p00_lo: u64 = (p00: u32): u64;
let p00_hi: u64 = p00 >> 32u64;
let mid1: u64 = p10 + p00_hi;
let mid1_lo: u64 = (mid1: u32): u64;
let mid1_hi: u64 = mid1 >> 32u64;
let mid2: u64 = p01 + mid1_lo;
let mid2_lo: u64 = (mid2: u32): u64;
let mid2_hi: u64 = mid2 >> 32u64;
let r_hi: u64 = p11 + mid1_hi + mid2_hi;
let r_lo: u64 = (mid2_lo << 32u64) | p00_lo;
return r128 { hi = r_hi, lo = r_lo };
};
// ref/hare/strconv/stof.ha:14.
fn todig(c: u8) u8 = {
if ('0' <= c && c <= '9') { return c - '0'; };
if ('a' <= c && c <= 'f') { return c - 'a' + 10u8; };
if ('A' <= c && c <= 'F') { return c - 'A' + 10u8; };
abort("strconv.todig: unreachable");
return 0u8; // unreachable; rt_abort is void-typed (path-cov)
};
@symbol("rt_abort") fn abort(msg: str) void;
// ref/hare/strconv/stof.ha:25.
type fast_parsed_float = struct {
mantissa: u64,
exponent: i32,
negative: bool,
truncated: bool,
};
// Digit-class predicate selector for fast_parse — replaces Hare's
// fn-pointer-in-tuple (`&ascii::isdigit` / `&ascii::isxdigit`).
fn isdigitbase(c: rune, ishex: bool) bool = {
if (ishex) { return ascii.isxdigit(c); };
return ascii.isdigit(c);
};
// ref/hare/strconv/stof.ha:32.
fn fast_parse(s: str, b: base) (fast_parsed_float | invalid) = {
let buf: []u8 = strings.toutf8(s);
let i: i32 = 0;
let neg: bool = false;
let trunc: bool = false;
if (buf[i] == '-') {
neg = true;
i += 1;
} else if (buf[i] == '+') {
i += 1;
};
let ishex: bool = (b == base.HEX);
let expchr: rune = 'e';
let max_ndmant: int = 19;
if (ishex) {
expchr = 'p';
max_ndmant = 16;
};
let bnum: u64 = (b: i32): u64;
let sawdot: bool = false;
let sawdigits: bool = false;
let nd: int = 0;
let ndmant: int = 0;
let dp: int = 0;
let mant: u64 = 0u64;
let exp: i32 = 0i32;
for (i < s.len) {
if (buf[i] == '.') {
if (sawdot) { return i: invalid; };
sawdot = true;
dp = nd;
} else if (isdigitbase(buf[i]: rune, ishex)) {
sawdigits = true;
if (buf[i] == '0' && nd == 0) {
dp -= 1;
i += 1;
continue;
};
nd += 1;
if (ndmant < max_ndmant) {
mant = mant * bnum + (todig(buf[i]): u64);
ndmant += 1;
} else if (buf[i] != '0') {
trunc = true;
};
} else {
break;
};
i += 1;
};
if (!sawdigits) { return i: invalid; };
if (!sawdot) {
dp = nd;
};
if (b == base.HEX) {
dp *= 4;
ndmant *= 4;
};
if (i < s.len && ascii.tolower(buf[i]: rune) == expchr) {
i += 1;
if (i >= s.len) { return i: invalid; };
let expsign: int = 1;
if (buf[i] == '+') {
i += 1;
} else if (buf[i] == '-') {
expsign = -1;
i += 1;
};
if (i >= s.len || !ascii.isdigit(buf[i]: rune)) {
return i: invalid;
};
let e: int = 0;
for (i < s.len && ascii.isdigit(buf[i]: rune)) {
if (e < 10000) {
e = e * 10 + ((buf[i] - '0'): int);
};
i += 1;
};
dp += e * expsign;
} else if (b == base.HEX) {
return i: invalid; // hex floats must have an exponent
};
if (i != s.len) { return i: invalid; };
if (mant != 0u64) {
exp = (dp - ndmant): i32;
};
return fast_parsed_float {
mantissa = mant,
exponent = exp,
negative = neg,
truncated = trunc,
};
};
// ref/hare/strconv/stof.ha:115. Fills the slow-path decimal `d`.
fn decimal_parse(d: *decimal, s: str) (void | invalid) = {
let i: i32 = 0;
let buf: []u8 = strings.toutf8(s);
d.negative = false;
d.truncated = false;
if (buf[0] == '+') {
i += 1;
} else if (buf[0] == '-') {
d.negative = true;
i += 1;
};
let sawdot: bool = false;
let sawdigits: bool = false;
for (i < s.len) {
if (buf[i] == '.') {
if (sawdot) { return i: invalid; };
sawdot = true;
d.dp = (d.nd: i32);
} else if (ascii.isdigit(buf[i]: rune)) {
sawdigits = true;
if (buf[i] == '0' && d.nd == (0u64: size)) {
d.dp -= 1;
i += 1;
continue;
};
if (d.nd < (len(d.digits): size)) {
d.digits[d.nd] = buf[i] - '0';
d.nd += (1u64: size);
} else if (buf[i] != '0') {
d.truncated = true;
};
} else {
break;
};
i += 1;
};
if (!sawdigits) { return i: invalid; };
if (!sawdot) {
d.dp = (d.nd: i32);
};
if (i < s.len && (buf[i] == 'e' || buf[i] == 'E')) {
i += 1;
if (i >= s.len) { return i: invalid; };
let expsign: int = 1;
if (buf[i] == '+') {
i += 1;
} else if (buf[i] == '-') {
expsign = -1;
i += 1;
};
if (i >= s.len || !ascii.isdigit(buf[i]: rune)) {
return i: invalid;
};
let e: int = 0;
for (i < s.len && ascii.isdigit(buf[i]: rune)) {
if (e < 10000) {
e = e * 10 + ((buf[i] - '0'): int);
};
i += 1;
};
d.dp += (e * expsign): i32;
};
if (i != s.len) { return i: invalid; };
return;
};
// ref/hare/strconv/stof.ha:173. Count of leading zero bits in n>0.
fn leading_zeroes(n: u64) uint = {
os.assert(n > 0u64, "strconv.leading_zeroes: n == 0");
let b: u64 = 0u64;
if ((n & 0xFFFFFFFF00000000u64) > 0u64) {
n >>= 32u64;
b |= 32u64;
};
if ((n & 0xFFFF0000u64) > 0u64) {
n >>= 16u64;
b |= 16u64;
};
if ((n & 0xFF00u64) > 0u64) {
n >>= 8u64;
b |= 8u64;
};
if ((n & 0xF0u64) > 0u64) {
n >>= 4u64;
b |= 4u64;
};
if ((n & 0xCu64) > 0u64) {
n >>= 2u64;
b |= 2u64;
};
if ((n & 0x2u64) > 0u64) {
n >>= 1u64;
b |= 1u64;
};
return ((63u64 - b): uint);
};
// ref/hare/strconv/stof.ha:203. Eisel-Lemire fast path: a correctly-
// rounded f64/f32 from (mantissa, exp10) when the 128-bit product is
// unambiguous, else void → caller falls to the decimal slow path.
// Divergences at-site: `mantissa <<= clz` (scalar-param mutate) → local
// `mnt`; whole-struct local reassign `x = merged` copies only the first
// word in cgen → per-field `x.hi = …; x.lo = …` (#155); `po10 =
// powers_of_ten[i]` row-bind → direct double-index (#155, A2); bitwise-
// vs-compare fully parenthesised; comma let-bindings split.
fn eisel_lemire(
mantissa: u64,
exp10: i32,
neg: bool,
f: *math.floatinfo,
) (u64 | void) = {
if (mantissa == 0u64 || exp10 > 288 || exp10 < -307) {
return;
};
let idx: i32 = exp10 + 307;
let clz: uint = leading_zeroes(mantissa);
let mnt: u64 = mantissa << (clz: u64);
let shift: u64 = 64u64 - f.mantbits - 3u64;
let mask: u64 = (1u64 << shift) - 1u64;
// log(10)/log(2) ≈ 217706 / 65536; x / 65536 = x >> 16.
let exp: int = (217706 * (exp10: int)) >> 16;
let e2: u64 = ((exp + f.expbias + 64): u64) - (clz: u64);
let x: r128 = u128mul(mnt, powers_of_ten[idx][1]);
if ((x.hi & mask) == mask && (x.lo + mnt) < mnt) {
let y: r128 = u128mul(mnt, powers_of_ten[idx][0]);
let merged: r128 = r128 { hi = x.hi, lo = x.lo + y.hi };
if (merged.lo < x.lo) {
// local-struct-field compound-assign drops the load in
// wwstage (sets =1, not +=1) — explicit form, byte-id.
merged.hi = merged.hi + 1u64;
};
if ((merged.hi & mask) == mask && (merged.lo + 1u64) == 0u64 &&
(y.lo + mnt) < mnt) {
return;
};
x.hi = merged.hi;
x.lo = merged.lo;
};
let msb: u64 = x.hi >> 63u64;
let mant: u64 = x.hi >> (msb + shift);
e2 -= 1u64 ^ msb;
if (x.lo == 0u64 && (x.hi & mask) == 0u64 && (mant & 3u64) == 1u64) {
return;
};
mant += mant & 1u64;
mant >>= 1u64;
if ((mant >> (f.mantbits + 1u64)) > 0u64) {
mant >>= 1u64;
e2 += 1u64;
};
if (e2 <= 0u64 || e2 >= (1u64 << f.expbits) - 1u64) {
return;
};
return mkfloat(mant, (e2: uint), neg, f);
};
// ref/hare/strconv/stof.ha:247. Slow-path: decimal `d` → IEEE bits.
fn floatbits(d: *decimal, f: *math.floatinfo) (u64 | overflow) = {
let e: int = 0;
let m: u64 = 0u64;
let powtab: [19]i8 = [
0i8, 3i8, 6i8, 9i8, 13i8, 16i8, 19i8, 23i8, 26i8, 29i8,
33i8, 36i8, 39i8, 43i8, 46i8, 49i8, 53i8, 56i8, 59i8,
];
if (d.nd == (0u64: size) || d.dp < -326) {
if (d.negative) {
return mkfloat(0u64, (0u32: uint), d.negative, f);
};
return 0u64;
} else if (d.dp > 310) {
return overflow{};
};
if (d.nd <= (19u64: size)) {
let dmant: u64 = 0u64;
let i: size = (0u64: size);
for (i < d.nd) {
dmant = 10u64 * dmant + (d.digits[i]: u64);
i += (1u64: size);
};
let exp10: i32 = d.dp - (d.nd: i32);
match (eisel_lemire(dmant, exp10, d.negative, f)) {
case let r: u64 => { return r; };
case void => void;
};
};
for (d.dp > 0) {
let n: int = 0;
if ((d.dp: uint) >= (len(powtab): uint)) {
n = (maxshift: int);
} else {
n = (powtab[d.dp]: int);
};
decimal_shift(d, -n);
e += n;
};
for (d.dp <= 0) {
let n: int = 0;
if (d.dp == 0) {
if (d.digits[0] >= 5u8) { break; };
if (d.digits[0] < 2u8) { n = 2; } else { n = 1; };
} else if ((-d.dp) >= (len(powtab): i32)) {
n = (maxshift: int);
} else {
n = (powtab[-d.dp]: int);
};
decimal_shift(d, n);
e -= n;
};
e -= 1;
if (e <= -f.expbias + 1) {
let nn: int = -f.expbias - e + 1;
decimal_shift(d, -nn);
e += nn;
};
if (e + f.expbias >= ((1u64 << f.expbits): int) - 1) {
return overflow{};
};
decimal_shift(d, (f.mantbits: int) + 1);
m = decimal_round(d);
if (m == (2u64 << f.mantbits)) {
m >>= 1u64;
e += 1;
if (e + f.expbias >= ((1u64 << f.expbits): int) - 1) {
return overflow{};
};
};
if ((m & (1u64 << f.mantbits)) == 0u64) {
e = -f.expbias;
};
return mkfloat(m, ((e + f.expbias): uint), d.negative, f);
};
// ref/hare/strconv/stof.ha:311. Assemble sign|exp|mantissa.
fn mkfloat(m: u64, e: uint, negative: bool, f: *math.floatinfo) u64 = {
let n: u64 = m & ((1u64 << f.mantbits) - 1u64);
n |= ((e: u64) & ((1u64 << f.expbits) - 1u64)) << f.mantbits;
if (negative) {
n |= 1u64 << (f.mantbits + f.expbits);
};
return n;
};
// ref/hare/strconv/stof.ha:320. Exact f64 powers of ten 1e0..1e22 (all
// exactly representable; see stof64exact).
let f64pow10: [23]f64 = [
1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9,
1.0e10, 1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17, 1.0e18,
1.0e19, 1.0e20, 1.0e21, 1.0e22,
];
// ref/hare/strconv/stof.ha:326.
fn stof64exact(mant: u64, exp: i32, neg: bool) (f64 | void) = {
if (mant >> math.F64_MANTISSA_BITS != 0u64) { return; };
let n: f64 = (mant: i64): f64;
if (neg) {
n = -n;
};
if (exp == 0i32) {
return n;
};
if (-22i32 <= exp && exp <= 22i32) {
if (exp >= 0i32) {
// f64 compound-assign mis-lowers in cgen — explicit
// form (strconv.ww f64tos precedent).
n = n * f64pow10[exp];
} else {
n = n / f64pow10[-exp];
};
} else {
return;
};
return n;
};
// ref/hare/strconv/stof.ha:345. Exact f32 powers of ten 1e0..1e10.
let f32pow10: [11]f32 = [
1.0e0f32, 1.0e1f32, 1.0e2f32, 1.0e3f32, 1.0e4f32, 1.0e5f32, 1.0e6f32,
1.0e7f32, 1.0e8f32, 1.0e9f32, 1.0e10f32,
];
// ref/hare/strconv/stof.ha:349.
fn stof32exact(mant: u64, exp: i32, neg: bool) (f32 | void) = {
if (mant >> (math.F32_MANTISSA_BITS: u64) != 0u64) { return; };
let n: f32 = (mant: i32): f32;
if (neg) {
n = -n;
};
if (exp == 0i32) {
return n;
};
if (-10i32 <= exp && exp <= 10i32) {
if (exp >= 0i32) {
// f32 compound-assign mis-lowers in cgen — explicit form.
n = n * f32pow10[exp];
} else {
n = n / (f64pow10[-exp]: f32);
};
} else {
return;
};
return n;
};
// ref/hare/strconv/stof.ha:369. Adapted from Go's atofHex. The by-value
// `p` is mutated in Hare; ww copies its fields to scalar locals (struct
// param field-write miscompiles + diverges — filed).
fn hex_to_bits(p: fast_parsed_float, info: *math.floatinfo) (u64 | overflow) = {
let pmant: u64 = p.mantissa;
let pexp: i32 = p.exponent;
let pneg: bool = p.negative;
let ptrunc: bool = p.truncated;
let max_exp: int = ((1u64 << info.expbits): int) - info.expbias - 2;
let min_exp: int = -info.expbias + 1;
pexp += (info.mantbits: i32);
// Shift left until a leading 1 bit followed by mantbits + 2 rounding.
for (pmant != 0u64 && pmant >> (info.mantbits + 2u64) == 0u64) {
pmant <<= 1u64;
pexp -= 1;
};
if (ptrunc) {
pmant |= 1u64;
};
// Too many bits: shift right (sticky-or the dropped bit).
for (pmant >> (3u64 + info.mantbits) != 0u64) {
pmant = (pmant >> 1u64) | (pmant & 1u64);
pexp += 1;
};
// Denormalise if the exponent is small.
for (pmant > 1u64 && pexp < (min_exp: i32) - 2) {
pmant = (pmant >> 1u64) | (pmant & 1u64);
pexp += 1;
};
// Round to even.
let round: u64 = pmant & 3u64;
pmant >>= 2u64;
round |= pmant & 1u64;
pexp += 2;
if (round == 3u64) {
pmant += 1u64;
if (pmant == 1u64 << (1u64 + info.mantbits)) {
pmant >>= 1u64;
pexp += 1;
};
};
// Denormal or zero.
if (pmant >> info.mantbits == 0u64) {
pexp = (-info.expbias): i32;
};
if (pexp > (max_exp: i32)) {
return overflow{};
};
let bits: u64 = pmant & info.mantmask;
bits |= (((pexp + (info.expbias: i32)): u64) & info.expmask) << info.mantbits;
if (pneg) {
bits |= 1u64 << (info.mantbits + info.expbits);
};
return bits;
};
// ref/hare/strconv/stof.ha:425. "nan"/"infinity"/±"infinity",
// case-insensitive. ww math has no f32 NAN/INF consts → f32frombits of
// the IEEE-754 f32 bit patterns (qNaN 0x7FC00000, ±Inf 0x7F800000 /
// 0xFF800000).
fn special(s: str) (f32 | void) = {
if (ascii.strcasecmp(s, "nan") == 0) {
return math.f32frombits(0x7FC00000u32);
} else if (ascii.strcasecmp(s, "infinity") == 0) {
return math.f32frombits(0x7F800000u32);
} else if (ascii.strcasecmp(s, "+infinity") == 0) {
return math.f32frombits(0x7F800000u32);
} else if (ascii.strcasecmp(s, "-infinity") == 0) {
return math.f32frombits(0xFF800000u32);
};
return;
};
// ref/hare/strconv/stof.ha:445. Parse `s` as f64 (base DEC or HEX). See
// the module note: the EL fast path is HELD; the decimal fallback gives
// correct results meanwhile.
export fn stof64(s: str, b: base) (f64 | invalid | overflow) = {
let bb: base = b;
if (bb == base.DEFAULT) {
bb = base.DEC;
} else if (bb == base.HEX_LOWER) {
bb = base.HEX;
};
os.assert(bb == base.DEC || bb == base.HEX,
"strconv.stof64: base must be DEC or HEX");
if (s.len == 0) {
return 0: invalid;
};
match (special(s)) {
case let f: f32 => { return (f: f64); };
case void => void;
};
match (fast_parse(s, bb)) {
case let p: fast_parsed_float => {
if (bb == base.HEX) {
match (hex_to_bits(p, &math.f64info)) {
case let bits: u64 => { return math.f64frombits(bits); };
case let eo: overflow => { return eo; };
};
} else if (!p.truncated) {
match (stof64exact(p.mantissa, p.exponent, p.negative)) {
case let n: f64 => { return n; };
case void => void;
};
match (eisel_lemire(p.mantissa, p.exponent, p.negative,
&math.f64info)) {
case let n: u64 => { return math.f64frombits(n); };
case void => void;
};
};
let d = decimal { ... };
match (decimal_parse(&d, s)) {
case let ei: invalid => { return ei; };
case void => void;
};
match (floatbits(&d, &math.f64info)) {
case let n: u64 => { return math.f64frombits(n); };
case let eo: overflow => { return eo; };
};
};
case let ei: invalid => { return ei; };
};
return 0: invalid; // unreachable (path-cov)
};
// ref/hare/strconv/stof.ha:491. Parse `s` as f32 (base DEC or HEX).
export fn stof32(s: str, b: base) (f32 | invalid | overflow) = {
let bb: base = b;
if (bb == base.DEFAULT) {
bb = base.DEC;
} else if (bb == base.HEX_LOWER) {
bb = base.HEX;
};
os.assert(bb == base.DEC || bb == base.HEX,
"strconv.stof32: base must be DEC or HEX");
if (s.len == 0) {
return 0: invalid;
};
match (special(s)) {
case let f: f32 => { return f; };
case void => void;
};
match (fast_parse(s, bb)) {
case let p: fast_parsed_float => {
if (bb == base.HEX) {
match (hex_to_bits(p, &math.f32info)) {
case let bits: u64 => {
return math.f32frombits(bits: u32);
};
case let eo: overflow => { return eo; };
};
} else if (!p.truncated) {
match (stof32exact(p.mantissa, p.exponent, p.negative)) {
case let n: f32 => { return n; };
case void => void;
};
match (eisel_lemire(p.mantissa, p.exponent, p.negative,
&math.f32info)) {
case let n: u64 => { return math.f32frombits(n: u32); };
case void => void;
};
};
let d = decimal { ... };
match (decimal_parse(&d, s)) {
case let ei: invalid => { return ei; };
case void => void;
};
match (floatbits(&d, &math.f32info)) {
case let n: u64 => { return math.f32frombits(n: u32); };
case let eo: overflow => { return eo; };
};
};
case let ei: invalid => { return ei; };
};
return 0: invalid; // unreachable (path-cov)
};

View File

@@ -11,10 +11,12 @@
// both stages agree on (candidate #130). // both stages agree on (candidate #130).
// //
// `powers_of_ten: [596][2]u64` (ref/hare/strconv/stof_data.ha:73) is the // `powers_of_ten: [596][2]u64` (ref/hare/strconv/stof_data.ha:73) is the
// Eisel-Lemire fast-path table and is only consumed by stof.ha (a later // Eisel-Lemire fast-path table (consumed by stof.ww's eisel_lemire); it
// fold); deferred to its consumer-driven port per CLAUDE.md rule 9 // lands here in fold-4 alongside its consumer, indexed `[exp10 + 307]`
// (Hare-fidelity is API-shaped, and module-level tables follow their // for exp10 in [-307, 288]. Faithful 2D `[596][2]u64` (the {hi,lo} pair
// caller's scope). // IS the 128-bit truncated power-of-ten; rule-12, not flattened) — the
// 2D module-level static-init + double-index read it needs landed in
// #156 (cbeffea). See the table at the foot of this file.
package strconv; package strconv;
@@ -93,3 +95,604 @@ let pow5_table: [0x051C]u8 = [
7u8, 3u8, 7u8, 9u8, 8u8, 8u8, 4u8, 0u8, 3u8, 5u8, 4u8, 7u8, 2u8, 0u8, 5u8, 9u8, 6u8, 2u8, 2u8, 4u8, 0u8, 6u8, 9u8, 5u8, 7u8, 3u8, 7u8, 9u8, 8u8, 8u8, 4u8, 0u8, 3u8, 5u8, 4u8, 7u8, 2u8, 0u8, 5u8, 9u8, 6u8, 2u8, 2u8, 4u8, 0u8, 6u8, 9u8, 5u8,
9u8, 5u8, 3u8, 3u8, 6u8, 9u8, 1u8, 4u8, 0u8, 6u8, 2u8, 5u8, 9u8, 5u8, 3u8, 3u8, 6u8, 9u8, 1u8, 4u8, 0u8, 6u8, 2u8, 5u8,
]; ];
// ref/hare/strconv/stof_data.ha:73. Eisel-Lemire 128-bit power-of-ten
// table (see header note). 596 rows, {hi, lo} u64 pair per row.
let powers_of_ten: [596][2]u64 = [
[0xA5D3B6D479F8E056u64, 0x8FD0C16206306BABu64],
[0x8F48A4899877186Cu64, 0xB3C4F1BA87BC8696u64],
[0x331ACDABFE94DE87u64, 0xE0B62E2929ABA83Cu64],
[0x9FF0C08B7F1D0B14u64, 0x8C71DCD9BA0B4925u64],
[0x07ECF0AE5EE44DD9u64, 0xAF8E5410288E1B6Fu64],
[0xC9E82CD9F69D6150u64, 0xDB71E91432B1A24Au64],
[0xBE311C083A225CD2u64, 0x892731AC9FAF056Eu64],
[0x6DBD630A48AAF406u64, 0xAB70FE17C79AC6CAu64],
[0x092CBBCCDAD5B108u64, 0xD64D3D9DB981787Du64],
[0x25BBF56008C58EA5u64, 0x85F0468293F0EB4Eu64],
[0xAF2AF2B80AF6F24Eu64, 0xA76C582338ED2621u64],
[0x1AF5AF660DB4AEE1u64, 0xD1476E2C07286FAAu64],
[0x50D98D9FC890ED4Du64, 0x82CCA4DB847945CAu64],
[0xE50FF107BAB528A0u64, 0xA37FCE126597973Cu64],
[0x1E53ED49A96272C8u64, 0xCC5FC196FEFD7D0Cu64],
[0x25E8E89C13BB0F7Au64, 0xFF77B1FCBEBCDC4Fu64],
[0x77B191618C54E9ACu64, 0x9FAACF3DF73609B1u64],
[0xD59DF5B9EF6A2417u64, 0xC795830D75038C1Du64],
[0x4B0573286B44AD1Du64, 0xF97AE3D0D2446F25u64],
[0x4EE367F9430AEC32u64, 0x9BECCE62836AC577u64],
[0x229C41F793CDA73Fu64, 0xC2E801FB244576D5u64],
[0x6B43527578C1110Fu64, 0xF3A20279ED56D48Au64],
[0x830A13896B78AAA9u64, 0x9845418C345644D6u64],
[0x23CC986BC656D553u64, 0xBE5691EF416BD60Cu64],
[0x2CBFBE86B7EC8AA8u64, 0xEDEC366B11C6CB8Fu64],
[0x7BF7D71432F3D6A9u64, 0x94B3A202EB1C3F39u64],
[0xDAF5CCD93FB0CC53u64, 0xB9E08A83A5E34F07u64],
[0xD1B3400F8F9CFF68u64, 0xE858AD248F5C22C9u64],
[0x23100809B9C21FA1u64, 0x91376C36D99995BEu64],
[0xABD40A0C2832A78Au64, 0xB58547448FFFFB2Du64],
[0x16C90C8F323F516Cu64, 0xE2E69915B3FFF9F9u64],
[0xAE3DA7D97F6792E3u64, 0x8DD01FAD907FFC3Bu64],
[0x99CD11CFDF41779Cu64, 0xB1442798F49FFB4Au64],
[0x40405643D711D583u64, 0xDD95317F31C7FA1Du64],
[0x482835EA666B2572u64, 0x8A7D3EEF7F1CFC52u64],
[0xDA3243650005EECFu64, 0xAD1C8EAB5EE43B66u64],
[0x90BED43E40076A82u64, 0xD863B256369D4A40u64],
[0x5A7744A6E804A291u64, 0x873E4F75E2224E68u64],
[0x711515D0A205CB36u64, 0xA90DE3535AAAE202u64],
[0x0D5A5B44CA873E03u64, 0xD3515C2831559A83u64],
[0xE858790AFE9486C2u64, 0x8412D9991ED58091u64],
[0x626E974DBE39A872u64, 0xA5178FFF668AE0B6u64],
[0xFB0A3D212DC8128Fu64, 0xCE5D73FF402D98E3u64],
[0x7CE66634BC9D0B99u64, 0x80FA687F881C7F8Eu64],
[0x1C1FFFC1EBC44E80u64, 0xA139029F6A239F72u64],
[0xA327FFB266B56220u64, 0xC987434744AC874Eu64],
[0x4BF1FF9F0062BAA8u64, 0xFBE9141915D7A922u64],
[0x6F773FC3603DB4A9u64, 0x9D71AC8FADA6C9B5u64],
[0xCB550FB4384D21D3u64, 0xC4CE17B399107C22u64],
[0x7E2A53A146606A48u64, 0xF6019DA07F549B2Bu64],
[0x2EDA7444CBFC426Du64, 0x99C102844F94E0FBu64],
[0xFA911155FEFB5308u64, 0xC0314325637A1939u64],
[0x793555AB7EBA27CAu64, 0xF03D93EEBC589F88u64],
[0x4BC1558B2F3458DEu64, 0x96267C7535B763B5u64],
[0x9EB1AAEDFB016F16u64, 0xBBB01B9283253CA2u64],
[0x465E15A979C1CADCu64, 0xEA9C227723EE8BCBu64],
[0x0BFACD89EC191EC9u64, 0x92A1958A7675175Fu64],
[0xCEF980EC671F667Bu64, 0xB749FAED14125D36u64],
[0x82B7E12780E7401Au64, 0xE51C79A85916F484u64],
[0xD1B2ECB8B0908810u64, 0x8F31CC0937AE58D2u64],
[0x861FA7E6DCB4AA15u64, 0xB2FE3F0B8599EF07u64],
[0x67A791E093E1D49Au64, 0xDFBDCECE67006AC9u64],
[0xE0C8BB2C5C6D24E0u64, 0x8BD6A141006042BDu64],
[0x58FAE9F773886E18u64, 0xAECC49914078536Du64],
[0xAF39A475506A899Eu64, 0xDA7F5BF590966848u64],
[0x6D8406C952429603u64, 0x888F99797A5E012Du64],
[0xC8E5087BA6D33B83u64, 0xAAB37FD7D8F58178u64],
[0xFB1E4A9A90880A64u64, 0xD5605FCDCF32E1D6u64],
[0x5CF2EEA09A55067Fu64, 0x855C3BE0A17FCD26u64],
[0xF42FAA48C0EA481Eu64, 0xA6B34AD8C9DFC06Fu64],
[0xF13B94DAF124DA26u64, 0xD0601D8EFC57B08Bu64],
[0x76C53D08D6B70858u64, 0x823C12795DB6CE57u64],
[0x54768C4B0C64CA6Eu64, 0xA2CB1717B52481EDu64],
[0xA9942F5DCF7DFD09u64, 0xCB7DDCDDA26DA268u64],
[0xD3F93B35435D7C4Cu64, 0xFE5D54150B090B02u64],
[0xC47BC5014A1A6DAFu64, 0x9EFA548D26E5A6E1u64],
[0x359AB6419CA1091Bu64, 0xC6B8E9B0709F109Au64],
[0xC30163D203C94B62u64, 0xF867241C8CC6D4C0u64],
[0x79E0DE63425DCF1Du64, 0x9B407691D7FC44F8u64],
[0x985915FC12F542E4u64, 0xC21094364DFB5636u64],
[0x3E6F5B7B17B2939Du64, 0xF294B943E17A2BC4u64],
[0xA705992CEECF9C42u64, 0x979CF3CA6CEC5B5Au64],
[0x50C6FF782A838353u64, 0xBD8430BD08277231u64],
[0xA4F8BF5635246428u64, 0xECE53CEC4A314EBDu64],
[0x871B7795E136BE99u64, 0x940F4613AE5ED136u64],
[0x28E2557B59846E3Fu64, 0xB913179899F68584u64],
[0x331AEADA2FE589CFu64, 0xE757DD7EC07426E5u64],
[0x3FF0D2C85DEF7621u64, 0x9096EA6F3848984Fu64],
[0x0FED077A756B53A9u64, 0xB4BCA50B065ABE63u64],
[0xD3E8495912C62894u64, 0xE1EBCE4DC7F16DFBu64],
[0x64712DD7ABBBD95Cu64, 0x8D3360F09CF6E4BDu64],
[0xBD8D794D96AACFB3u64, 0xB080392CC4349DECu64],
[0xECF0D7A0FC5583A0u64, 0xDCA04777F541C567u64],
[0xF41686C49DB57244u64, 0x89E42CAAF9491B60u64],
[0x311C2875C522CED5u64, 0xAC5D37D5B79B6239u64],
[0x7D633293366B828Bu64, 0xD77485CB25823AC7u64],
[0xAE5DFF9C02033197u64, 0x86A8D39EF77164BCu64],
[0xD9F57F830283FDFCu64, 0xA8530886B54DBDEBu64],
[0xD072DF63C324FD7Bu64, 0xD267CAA862A12D66u64],
[0x4247CB9E59F71E6Du64, 0x8380DEA93DA4BC60u64],
[0x52D9BE85F074E608u64, 0xA46116538D0DEB78u64],
[0x67902E276C921F8Bu64, 0xCD795BE870516656u64],
[0x00BA1CD8A3DB53B6u64, 0x806BD9714632DFF6u64],
[0x80E8A40ECCD228A4u64, 0xA086CFCD97BF97F3u64],
[0x6122CD128006B2CDu64, 0xC8A883C0FDAF7DF0u64],
[0x796B805720085F81u64, 0xFAD2A4B13D1B5D6Cu64],
[0xCBE3303674053BB0u64, 0x9CC3A6EEC6311A63u64],
[0xBEDBFC4411068A9Cu64, 0xC3F490AA77BD60FCu64],
[0xEE92FB5515482D44u64, 0xF4F1B4D515ACB93Bu64],
[0x751BDD152D4D1C4Au64, 0x991711052D8BF3C5u64],
[0xD262D45A78A0635Du64, 0xBF5CD54678EEF0B6u64],
[0x86FB897116C87C34u64, 0xEF340A98172AACE4u64],
[0xD45D35E6AE3D4DA0u64, 0x9580869F0E7AAC0Eu64],
[0x8974836059CCA109u64, 0xBAE0A846D2195712u64],
[0x2BD1A438703FC94Bu64, 0xE998D258869FACD7u64],
[0x7B6306A34627DDCFu64, 0x91FF83775423CC06u64],
[0x1A3BC84C17B1D542u64, 0xB67F6455292CBF08u64],
[0x20CABA5F1D9E4A93u64, 0xE41F3D6A7377EECAu64],
[0x547EB47B7282EE9Cu64, 0x8E938662882AF53Eu64],
[0xE99E619A4F23AA43u64, 0xB23867FB2A35B28Du64],
[0x6405FA00E2EC94D4u64, 0xDEC681F9F4C31F31u64],
[0xDE83BC408DD3DD04u64, 0x8B3C113C38F9F37Eu64],
[0x9624AB50B148D445u64, 0xAE0B158B4738705Eu64],
[0x3BADD624DD9B0957u64, 0xD98DDAEE19068C76u64],
[0xE54CA5D70A80E5D6u64, 0x87F8A8D4CFA417C9u64],
[0x5E9FCF4CCD211F4Cu64, 0xA9F6D30A038D1DBCu64],
[0x7647C3200069671Fu64, 0xD47487CC8470652Bu64],
[0x29ECD9F40041E073u64, 0x84C8D4DFD2C63F3Bu64],
[0xF468107100525890u64, 0xA5FB0A17C777CF09u64],
[0x7182148D4066EEB4u64, 0xCF79CC9DB955C2CCu64],
[0xC6F14CD848405530u64, 0x81AC1FE293D599BFu64],
[0xB8ADA00E5A506A7Cu64, 0xA21727DB38CB002Fu64],
[0xA6D90811F0E4851Cu64, 0xCA9CF1D206FDC03Bu64],
[0x908F4A166D1DA663u64, 0xFD442E4688BD304Au64],
[0x9A598E4E043287FEu64, 0x9E4A9CEC15763E2Eu64],
[0x40EFF1E1853F29FDu64, 0xC5DD44271AD3CDBAu64],
[0xD12BEE59E68EF47Cu64, 0xF7549530E188C128u64],
[0x82BB74F8301958CEu64, 0x9A94DD3E8CF578B9u64],
[0xE36A52363C1FAF01u64, 0xC13A148E3032D6E7u64],
[0xDC44E6C3CB279AC1u64, 0xF18899B1BC3F8CA1u64],
[0x29AB103A5EF8C0B9u64, 0x96F5600F15A7B7E5u64],
[0x7415D448F6B6F0E7u64, 0xBCB2B812DB11A5DEu64],
[0x111B495B3464AD21u64, 0xEBDF661791D60F56u64],
[0xCAB10DD900BEEC34u64, 0x936B9FCEBB25C995u64],
[0x3D5D514F40EEA742u64, 0xB84687C269EF3BFBu64],
[0x0CB4A5A3112A5112u64, 0xE65829B3046B0AFAu64],
[0x47F0E785EABA72ABu64, 0x8FF71A0FE2C2E6DCu64],
[0x59ED216765690F56u64, 0xB3F4E093DB73A093u64],
[0x306869C13EC3532Cu64, 0xE0F218B8D25088B8u64],
[0x1E414218C73A13FBu64, 0x8C974F7383725573u64],
[0xE5D1929EF90898FAu64, 0xAFBD2350644EEACFu64],
[0xDF45F746B74ABF39u64, 0xDBAC6C247D62A583u64],
[0x6B8BBA8C328EB783u64, 0x894BC396CE5DA772u64],
[0x066EA92F3F326564u64, 0xAB9EB47C81F5114Fu64],
[0xC80A537B0EFEFEBDu64, 0xD686619BA27255A2u64],
[0xBD06742CE95F5F36u64, 0x8613FD0145877585u64],
[0x2C48113823B73704u64, 0xA798FC4196E952E7u64],
[0xF75A15862CA504C5u64, 0xD17F3B51FCA3A7A0u64],
[0x9A984D73DBE722FBu64, 0x82EF85133DE648C4u64],
[0xC13E60D0D2E0EBBAu64, 0xA3AB66580D5FDAF5u64],
[0x318DF905079926A8u64, 0xCC963FEE10B7D1B3u64],
[0xFDF17746497F7052u64, 0xFFBBCFE994E5C61Fu64],
[0xFEB6EA8BEDEFA633u64, 0x9FD561F1FD0F9BD3u64],
[0xFE64A52EE96B8FC0u64, 0xC7CABA6E7C5382C8u64],
[0x3DFDCE7AA3C673B0u64, 0xF9BD690A1B68637Bu64],
[0x06BEA10CA65C084Eu64, 0x9C1661A651213E2Du64],
[0x486E494FCFF30A62u64, 0xC31BFA0FE5698DB8u64],
[0x5A89DBA3C3EFCCFAu64, 0xF3E2F893DEC3F126u64],
[0xF89629465A75E01Cu64, 0x986DDB5C6B3A76B7u64],
[0xF6BBB397F1135823u64, 0xBE89523386091465u64],
[0x746AA07DED582E2Cu64, 0xEE2BA6C0678B597Fu64],
[0xA8C2A44EB4571CDCu64, 0x94DB483840B717EFu64],
[0x92F34D62616CE413u64, 0xBA121A4650E4DDEBu64],
[0x77B020BAF9C81D17u64, 0xE896A0D7E51E1566u64],
[0x0ACE1474DC1D122Eu64, 0x915E2486EF32CD60u64],
[0x0D819992132456BAu64, 0xB5B5ADA8AAFF80B8u64],
[0x10E1FFF697ED6C69u64, 0xE3231912D5BF60E6u64],
[0xCA8D3FFA1EF463C1u64, 0x8DF5EFABC5979C8Fu64],
[0xBD308FF8A6B17CB2u64, 0xB1736B96B6FD83B3u64],
[0xAC7CB3F6D05DDBDEu64, 0xDDD0467C64BCE4A0u64],
[0x6BCDF07A423AA96Bu64, 0x8AA22C0DBEF60EE4u64],
[0x86C16C98D2C953C6u64, 0xAD4AB7112EB3929Du64],
[0xE871C7BF077BA8B7u64, 0xD89D64D57A607744u64],
[0x11471CD764AD4972u64, 0x87625F056C7C4A8Bu64],
[0xD598E40D3DD89BCFu64, 0xA93AF6C6C79B5D2Du64],
[0x4AFF1D108D4EC2C3u64, 0xD389B47879823479u64],
[0xCEDF722A585139BAu64, 0x843610CB4BF160CBu64],
[0xC2974EB4EE658828u64, 0xA54394FE1EEDB8FEu64],
[0x733D226229FEEA32u64, 0xCE947A3DA6A9273Eu64],
[0x0806357D5A3F525Fu64, 0x811CCC668829B887u64],
[0xCA07C2DCB0CF26F7u64, 0xA163FF802A3426A8u64],
[0xFC89B393DD02F0B5u64, 0xC9BCFF6034C13052u64],
[0xBBAC2078D443ACE2u64, 0xFC2C3F3841F17C67u64],
[0xD54B944B84AA4C0Du64, 0x9D9BA7832936EDC0u64],
[0x0A9E795E65D4DF11u64, 0xC5029163F384A931u64],
[0x4D4617B5FF4A16D5u64, 0xF64335BCF065D37Du64],
[0x504BCED1BF8E4E45u64, 0x99EA0196163FA42Eu64],
[0xE45EC2862F71E1D6u64, 0xC06481FB9BCF8D39u64],
[0x5D767327BB4E5A4Cu64, 0xF07DA27A82C37088u64],
[0x3A6A07F8D510F86Fu64, 0x964E858C91BA2655u64],
[0x890489F70A55368Bu64, 0xBBE226EFB628AFEAu64],
[0x2B45AC74CCEA842Eu64, 0xEADAB0ABA3B2DBE5u64],
[0x3B0B8BC90012929Du64, 0x92C8AE6B464FC96Fu64],
[0x09CE6EBB40173744u64, 0xB77ADA0617E3BBCBu64],
[0xCC420A6A101D0515u64, 0xE55990879DDCAABDu64],
[0x9FA946824A12232Du64, 0x8F57FA54C2A9EAB6u64],
[0x47939822DC96ABF9u64, 0xB32DF8E9F3546564u64],
[0x59787E2B93BC56F7u64, 0xDFF9772470297EBDu64],
[0x57EB4EDB3C55B65Au64, 0x8BFBEA76C619EF36u64],
[0xEDE622920B6B23F1u64, 0xAEFAE51477A06B03u64],
[0xE95FAB368E45ECEDu64, 0xDAB99E59958885C4u64],
[0x11DBCB0218EBB414u64, 0x88B402F7FD75539Bu64],
[0xD652BDC29F26A119u64, 0xAAE103B5FCD2A881u64],
[0x4BE76D3346F0495Fu64, 0xD59944A37C0752A2u64],
[0x6F70A4400C562DDBu64, 0x857FCAE62D8493A5u64],
[0xCB4CCD500F6BB952u64, 0xA6DFBD9FB8E5B88Eu64],
[0x7E2000A41346A7A7u64, 0xD097AD07A71F26B2u64],
[0x8ED400668C0C28C8u64, 0x825ECC24C873782Fu64],
[0x728900802F0F32FAu64, 0xA2F67F2DFA90563Bu64],
[0x4F2B40A03AD2FFB9u64, 0xCBB41EF979346BCAu64],
[0xE2F610C84987BFA8u64, 0xFEA126B7D78186BCu64],
[0x0DD9CA7D2DF4D7C9u64, 0x9F24B832E6B0F436u64],
[0x91503D1C79720DBBu64, 0xC6EDE63FA05D3143u64],
[0x75A44C6397CE912Au64, 0xF8A95FCF88747D94u64],
[0xC986AFBE3EE11ABAu64, 0x9B69DBE1B548CE7Cu64],
[0xFBE85BADCE996168u64, 0xC24452DA229B021Bu64],
[0xFAE27299423FB9C3u64, 0xF2D56790AB41C2A2u64],
[0xDCCD879FC967D41Au64, 0x97C560BA6B0919A5u64],
[0x5400E987BBC1C920u64, 0xBDB6B8E905CB600Fu64],
[0x290123E9AAB23B68u64, 0xED246723473E3813u64],
[0xF9A0B6720AAF6521u64, 0x9436C0760C86E30Bu64],
[0xF808E40E8D5B3E69u64, 0xB94470938FA89BCEu64],
[0xB60B1D1230B20E04u64, 0xE7958CB87392C2C2u64],
[0xB1C6F22B5E6F48C2u64, 0x90BD77F3483BB9B9u64],
[0x1E38AEB6360B1AF3u64, 0xB4ECD5F01A4AA828u64],
[0x25C6DA63C38DE1B0u64, 0xE2280B6C20DD5232u64],
[0x579C487E5A38AD0Eu64, 0x8D590723948A535Fu64],
[0x2D835A9DF0C6D851u64, 0xB0AF48EC79ACE837u64],
[0xF8E431456CF88E65u64, 0xDCDB1B2798182244u64],
[0x1B8E9ECB641B58FFu64, 0x8A08F0F8BF0F156Bu64],
[0xE272467E3D222F3Fu64, 0xAC8B2D36EED2DAC5u64],
[0x5B0ED81DCC6ABB0Fu64, 0xD7ADF884AA879177u64],
[0x98E947129FC2B4E9u64, 0x86CCBB52EA94BAEAu64],
[0x3F2398D747B36224u64, 0xA87FEA27A539E9A5u64],
[0x8EEC7F0D19A03AADu64, 0xD29FE4B18E88640Eu64],
[0x1953CF68300424ACu64, 0x83A3EEEEF9153E89u64],
[0x5FA8C3423C052DD7u64, 0xA48CEAAAB75A8E2Bu64],
[0x3792F412CB06794Du64, 0xCDB02555653131B6u64],
[0xE2BBD88BBEE40BD0u64, 0x808E17555F3EBF11u64],
[0x5B6ACEAEAE9D0EC4u64, 0xA0B19D2AB70E6ED6u64],
[0xF245825A5A445275u64, 0xC8DE047564D20A8Bu64],
[0xEED6E2F0F0D56712u64, 0xFB158592BE068D2Eu64],
[0x55464DD69685606Bu64, 0x9CED737BB6C4183Du64],
[0xAA97E14C3C26B886u64, 0xC428D05AA4751E4Cu64],
[0xD53DD99F4B3066A8u64, 0xF53304714D9265DFu64],
[0xE546A8038EFE4029u64, 0x993FE2C6D07B7FABu64],
[0xDE98520472BDD033u64, 0xBF8FDB78849A5F96u64],
[0x963E66858F6D4440u64, 0xEF73D256A5C0F77Cu64],
[0xDDE7001379A44AA8u64, 0x95A8637627989AADu64],
[0x5560C018580D5D52u64, 0xBB127C53B17EC159u64],
[0xAAB8F01E6E10B4A6u64, 0xE9D71B689DDE71AFu64],
[0xCAB3961304CA70E8u64, 0x9226712162AB070Du64],
[0x3D607B97C5FD0D22u64, 0xB6B00D69BB55C8D1u64],
[0x8CB89A7DB77C506Au64, 0xE45C10C42A2B3B05u64],
[0x77F3608E92ADB242u64, 0x8EB98A7A9A5B04E3u64],
[0x55F038B237591ED3u64, 0xB267ED1940F1C61Cu64],
[0x6B6C46DEC52F6688u64, 0xDF01E85F912E37A3u64],
[0x2323AC4B3B3DA015u64, 0x8B61313BBABCE2C6u64],
[0xABEC975E0A0D081Au64, 0xAE397D8AA96C1B77u64],
[0x96E7BD358C904A21u64, 0xD9C7DCED53C72255u64],
[0x7E50D64177DA2E54u64, 0x881CEA14545C7575u64],
[0xDDE50BD1D5D0B9E9u64, 0xAA242499697392D2u64],
[0x955E4EC64B44E864u64, 0xD4AD2DBFC3D07787u64],
[0xBD5AF13BEF0B113Eu64, 0x84EC3C97DA624AB4u64],
[0xECB1AD8AEACDD58Eu64, 0xA6274BBDD0FADD61u64],
[0x67DE18EDA5814AF2u64, 0xCFB11EAD453994BAu64],
[0x80EACF948770CED7u64, 0x81CEB32C4B43FCF4u64],
[0xA1258379A94D028Du64, 0xA2425FF75E14FC31u64],
[0x096EE45813A04330u64, 0xCAD2F7F5359A3B3Eu64],
[0x8BCA9D6E188853FCu64, 0xFD87B5F28300CA0Du64],
[0x775EA264CF55347Du64, 0x9E74D1B791E07E48u64],
[0x95364AFE032A819Du64, 0xC612062576589DDAu64],
[0x3A83DDBD83F52204u64, 0xF79687AED3EEC551u64],
[0xC4926A9672793542u64, 0x9ABE14CD44753B52u64],
[0x75B7053C0F178293u64, 0xC16D9A0095928A27u64],
[0x5324C68B12DD6338u64, 0xF1C90080BAF72CB1u64],
[0xD3F6FC16EBCA5E03u64, 0x971DA05074DA7BEEu64],
[0x88F4BB1CA6BCF584u64, 0xBCE5086492111AEAu64],
[0x2B31E9E3D06C32E5u64, 0xEC1E4A7DB69561A5u64],
[0x3AFF322E62439FCFu64, 0x9392EE8E921D5D07u64],
[0x09BEFEB9FAD487C2u64, 0xB877AA3236A4B449u64],
[0x4C2EBE687989A9B3u64, 0xE69594BEC44DE15Bu64],
[0x0F9D37014BF60A10u64, 0x901D7CF73AB0ACD9u64],
[0x538484C19EF38C94u64, 0xB424DC35095CD80Fu64],
[0x2865A5F206B06FB9u64, 0xE12E13424BB40E13u64],
[0xF93F87B7442E45D3u64, 0x8CBCCC096F5088CBu64],
[0xF78F69A51539D748u64, 0xAFEBFF0BCB24AAFEu64],
[0xB573440E5A884D1Bu64, 0xDBE6FECEBDEDD5BEu64],
[0x31680A88F8953030u64, 0x89705F4136B4A597u64],
[0xFDC20D2B36BA7C3Du64, 0xABCC77118461CEFCu64],
[0x3D32907604691B4Cu64, 0xD6BF94D5E57A42BCu64],
[0xA63F9A49C2C1B10Fu64, 0x8637BD05AF6C69B5u64],
[0x0FCF80DC33721D53u64, 0xA7C5AC471B478423u64],
[0xD3C36113404EA4A8u64, 0xD1B71758E219652Bu64],
[0x645A1CAC083126E9u64, 0x83126E978D4FDF3Bu64],
[0x3D70A3D70A3D70A3u64, 0xA3D70A3D70A3D70Au64],
[0xCCCCCCCCCCCCCCCCu64, 0xCCCCCCCCCCCCCCCCu64],
[0x0000000000000000u64, 0x8000000000000000u64],
[0x0000000000000000u64, 0xA000000000000000u64],
[0x0000000000000000u64, 0xC800000000000000u64],
[0x0000000000000000u64, 0xFA00000000000000u64],
[0x0000000000000000u64, 0x9C40000000000000u64],
[0x0000000000000000u64, 0xC350000000000000u64],
[0x0000000000000000u64, 0xF424000000000000u64],
[0x0000000000000000u64, 0x9896800000000000u64],
[0x0000000000000000u64, 0xBEBC200000000000u64],
[0x0000000000000000u64, 0xEE6B280000000000u64],
[0x0000000000000000u64, 0x9502F90000000000u64],
[0x0000000000000000u64, 0xBA43B74000000000u64],
[0x0000000000000000u64, 0xE8D4A51000000000u64],
[0x0000000000000000u64, 0x9184E72A00000000u64],
[0x0000000000000000u64, 0xB5E620F480000000u64],
[0x0000000000000000u64, 0xE35FA931A0000000u64],
[0x0000000000000000u64, 0x8E1BC9BF04000000u64],
[0x0000000000000000u64, 0xB1A2BC2EC5000000u64],
[0x0000000000000000u64, 0xDE0B6B3A76400000u64],
[0x0000000000000000u64, 0x8AC7230489E80000u64],
[0x0000000000000000u64, 0xAD78EBC5AC620000u64],
[0x0000000000000000u64, 0xD8D726B7177A8000u64],
[0x0000000000000000u64, 0x878678326EAC9000u64],
[0x0000000000000000u64, 0xA968163F0A57B400u64],
[0x0000000000000000u64, 0xD3C21BCECCEDA100u64],
[0x0000000000000000u64, 0x84595161401484A0u64],
[0x0000000000000000u64, 0xA56FA5B99019A5C8u64],
[0x0000000000000000u64, 0xCECB8F27F4200F3Au64],
[0x4000000000000000u64, 0x813F3978F8940984u64],
[0x5000000000000000u64, 0xA18F07D736B90BE5u64],
[0xA400000000000000u64, 0xC9F2C9CD04674EDEu64],
[0x4D00000000000000u64, 0xFC6F7C4045812296u64],
[0xF020000000000000u64, 0x9DC5ADA82B70B59Du64],
[0x6C28000000000000u64, 0xC5371912364CE305u64],
[0xC732000000000000u64, 0xF684DF56C3E01BC6u64],
[0x3C7F400000000000u64, 0x9A130B963A6C115Cu64],
[0x4B9F100000000000u64, 0xC097CE7BC90715B3u64],
[0x1E86D40000000000u64, 0xF0BDC21ABB48DB20u64],
[0x1314448000000000u64, 0x96769950B50D88F4u64],
[0x17D955A000000000u64, 0xBC143FA4E250EB31u64],
[0x5DCFAB0800000000u64, 0xEB194F8E1AE525FDu64],
[0x5AA1CAE500000000u64, 0x92EFD1B8D0CF37BEu64],
[0xF14A3D9E40000000u64, 0xB7ABC627050305ADu64],
[0x6D9CCD05D0000000u64, 0xE596B7B0C643C719u64],
[0xE4820023A2000000u64, 0x8F7E32CE7BEA5C6Fu64],
[0xDDA2802C8A800000u64, 0xB35DBF821AE4F38Bu64],
[0xD50B2037AD200000u64, 0xE0352F62A19E306Eu64],
[0x4526F422CC340000u64, 0x8C213D9DA502DE45u64],
[0x9670B12B7F410000u64, 0xAF298D050E4395D6u64],
[0x3C0CDD765F114000u64, 0xDAF3F04651D47B4Cu64],
[0xA5880A69FB6AC800u64, 0x88D8762BF324CD0Fu64],
[0x8EEA0D047A457A00u64, 0xAB0E93B6EFEE0053u64],
[0x72A4904598D6D880u64, 0xD5D238A4ABE98068u64],
[0x47A6DA2B7F864750u64, 0x85A36366EB71F041u64],
[0x999090B65F67D924u64, 0xA70C3C40A64E6C51u64],
[0xFFF4B4E3F741CF6Du64, 0xD0CF4B50CFE20765u64],
[0xBFF8F10E7A8921A4u64, 0x82818F1281ED449Fu64],
[0xAFF72D52192B6A0Du64, 0xA321F2D7226895C7u64],
[0x9BF4F8A69F764490u64, 0xCBEA6F8CEB02BB39u64],
[0x02F236D04753D5B4u64, 0xFEE50B7025C36A08u64],
[0x01D762422C946590u64, 0x9F4F2726179A2245u64],
[0x424D3AD2B7B97EF5u64, 0xC722F0EF9D80AAD6u64],
[0xD2E0898765A7DEB2u64, 0xF8EBAD2B84E0D58Bu64],
[0x63CC55F49F88EB2Fu64, 0x9B934C3B330C8577u64],
[0x3CBF6B71C76B25FBu64, 0xC2781F49FFCFA6D5u64],
[0x8BEF464E3945EF7Au64, 0xF316271C7FC3908Au64],
[0x97758BF0E3CBB5ACu64, 0x97EDD871CFDA3A56u64],
[0x3D52EEED1CBEA317u64, 0xBDE94E8E43D0C8ECu64],
[0x4CA7AAA863EE4BDDu64, 0xED63A231D4C4FB27u64],
[0x8FE8CAA93E74EF6Au64, 0x945E455F24FB1CF8u64],
[0xB3E2FD538E122B44u64, 0xB975D6B6EE39E436u64],
[0x60DBBCA87196B616u64, 0xE7D34C64A9C85D44u64],
[0xBC8955E946FE31CDu64, 0x90E40FBEEA1D3A4Au64],
[0x6BABAB6398BDBE41u64, 0xB51D13AEA4A488DDu64],
[0xC696963C7EED2DD1u64, 0xE264589A4DCDAB14u64],
[0xFC1E1DE5CF543CA2u64, 0x8D7EB76070A08AECu64],
[0x3B25A55F43294BCBu64, 0xB0DE65388CC8ADA8u64],
[0x49EF0EB713F39EBEu64, 0xDD15FE86AFFAD912u64],
[0x6E3569326C784337u64, 0x8A2DBF142DFCC7ABu64],
[0x49C2C37F07965404u64, 0xACB92ED9397BF996u64],
[0xDC33745EC97BE906u64, 0xD7E77A8F87DAF7FBu64],
[0x69A028BB3DED71A3u64, 0x86F0AC99B4E8DAFDu64],
[0xC40832EA0D68CE0Cu64, 0xA8ACD7C0222311BCu64],
[0xF50A3FA490C30190u64, 0xD2D80DB02AABD62Bu64],
[0x792667C6DA79E0FAu64, 0x83C7088E1AAB65DBu64],
[0x577001B891185938u64, 0xA4B8CAB1A1563F52u64],
[0xED4C0226B55E6F86u64, 0xCDE6FD5E09ABCF26u64],
[0x544F8158315B05B4u64, 0x80B05E5AC60B6178u64],
[0x696361AE3DB1C721u64, 0xA0DC75F1778E39D6u64],
[0x03BC3A19CD1E38E9u64, 0xC913936DD571C84Cu64],
[0x04AB48A04065C723u64, 0xFB5878494ACE3A5Fu64],
[0x62EB0D64283F9C76u64, 0x9D174B2DCEC0E47Bu64],
[0x3BA5D0BD324F8394u64, 0xC45D1DF942711D9Au64],
[0xCA8F44EC7EE36479u64, 0xF5746577930D6500u64],
[0x7E998B13CF4E1ECBu64, 0x9968BF6ABBE85F20u64],
[0x9E3FEDD8C321A67Eu64, 0xBFC2EF456AE276E8u64],
[0xC5CFE94EF3EA101Eu64, 0xEFB3AB16C59B14A2u64],
[0xBBA1F1D158724A12u64, 0x95D04AEE3B80ECE5u64],
[0x2A8A6E45AE8EDC97u64, 0xBB445DA9CA61281Fu64],
[0xF52D09D71A3293BDu64, 0xEA1575143CF97226u64],
[0x593C2626705F9C56u64, 0x924D692CA61BE758u64],
[0x6F8B2FB00C77836Cu64, 0xB6E0C377CFA2E12Eu64],
[0x0B6DFB9C0F956447u64, 0xE498F455C38B997Au64],
[0x4724BD4189BD5EACu64, 0x8EDF98B59A373FECu64],
[0x58EDEC91EC2CB657u64, 0xB2977EE300C50FE7u64],
[0x2F2967B66737E3EDu64, 0xDF3D5E9BC0F653E1u64],
[0xBD79E0D20082EE74u64, 0x8B865B215899F46Cu64],
[0xECD8590680A3AA11u64, 0xAE67F1E9AEC07187u64],
[0xE80E6F4820CC9495u64, 0xDA01EE641A708DE9u64],
[0x3109058D147FDCDDu64, 0x884134FE908658B2u64],
[0xBD4B46F0599FD415u64, 0xAA51823E34A7EEDEu64],
[0x6C9E18AC7007C91Au64, 0xD4E5E2CDC1D1EA96u64],
[0x03E2CF6BC604DDB0u64, 0x850FADC09923329Eu64],
[0x84DB8346B786151Cu64, 0xA6539930BF6BFF45u64],
[0xE612641865679A63u64, 0xCFE87F7CEF46FF16u64],
[0x4FCB7E8F3F60C07Eu64, 0x81F14FAE158C5F6Eu64],
[0xE3BE5E330F38F09Du64, 0xA26DA3999AEF7749u64],
[0x5CADF5BFD3072CC5u64, 0xCB090C8001AB551Cu64],
[0x73D9732FC7C8F7F6u64, 0xFDCB4FA002162A63u64],
[0x2867E7FDDCDD9AFAu64, 0x9E9F11C4014DDA7Eu64],
[0xB281E1FD541501B8u64, 0xC646D63501A1511Du64],
[0x1F225A7CA91A4226u64, 0xF7D88BC24209A565u64],
[0x3375788DE9B06958u64, 0x9AE757596946075Fu64],
[0x0052D6B1641C83AEu64, 0xC1A12D2FC3978937u64],
[0xC0678C5DBD23A49Au64, 0xF209787BB47D6B84u64],
[0xF840B7BA963646E0u64, 0x9745EB4D50CE6332u64],
[0xB650E5A93BC3D898u64, 0xBD176620A501FBFFu64],
[0xA3E51F138AB4CEBEu64, 0xEC5D3FA8CE427AFFu64],
[0xC66F336C36B10137u64, 0x93BA47C980E98CDFu64],
[0xB80B0047445D4184u64, 0xB8A8D9BBE123F017u64],
[0xA60DC059157491E5u64, 0xE6D3102AD96CEC1Du64],
[0x87C89837AD68DB2Fu64, 0x9043EA1AC7E41392u64],
[0x29BABE4598C311FBu64, 0xB454E4A179DD1877u64],
[0xF4296DD6FEF3D67Au64, 0xE16A1DC9D8545E94u64],
[0x1899E4A65F58660Cu64, 0x8CE2529E2734BB1Du64],
[0x5EC05DCFF72E7F8Fu64, 0xB01AE745B101E9E4u64],
[0x76707543F4FA1F73u64, 0xDC21A1171D42645Du64],
[0x6A06494A791C53A8u64, 0x899504AE72497EBAu64],
[0x0487DB9D17636892u64, 0xABFA45DA0EDBDE69u64],
[0x45A9D2845D3C42B6u64, 0xD6F8D7509292D603u64],
[0x0B8A2392BA45A9B2u64, 0x865B86925B9BC5C2u64],
[0x8E6CAC7768D7141Eu64, 0xA7F26836F282B732u64],
[0x3207D795430CD926u64, 0xD1EF0244AF2364FFu64],
[0x7F44E6BD49E807B8u64, 0x8335616AED761F1Fu64],
[0x5F16206C9C6209A6u64, 0xA402B9C5A8D3A6E7u64],
[0x36DBA887C37A8C0Fu64, 0xCD036837130890A1u64],
[0xC2494954DA2C9789u64, 0x802221226BE55A64u64],
[0xF2DB9BAA10B7BD6Cu64, 0xA02AA96B06DEB0FDu64],
[0x6F92829494E5ACC7u64, 0xC83553C5C8965D3Du64],
[0xCB772339BA1F17F9u64, 0xFA42A8B73ABBF48Cu64],
[0xFF2A760414536EFBu64, 0x9C69A97284B578D7u64],
[0xFEF5138519684ABAu64, 0xC38413CF25E2D70Du64],
[0x7EB258665FC25D69u64, 0xF46518C2EF5B8CD1u64],
[0xEF2F773FFBD97A61u64, 0x98BF2F79D5993802u64],
[0xAAFB550FFACFD8FAu64, 0xBEEEFB584AFF8603u64],
[0x95BA2A53F983CF38u64, 0xEEAABA2E5DBF6784u64],
[0xDD945A747BF26183u64, 0x952AB45CFA97A0B2u64],
[0x94F971119AEEF9E4u64, 0xBA756174393D88DFu64],
[0x7A37CD5601AAB85Du64, 0xE912B9D1478CEB17u64],
[0xAC62E055C10AB33Au64, 0x91ABB422CCB812EEu64],
[0x577B986B314D6009u64, 0xB616A12B7FE617AAu64],
[0xED5A7E85FDA0B80Bu64, 0xE39C49765FDF9D94u64],
[0x14588F13BE847307u64, 0x8E41ADE9FBEBC27Du64],
[0x596EB2D8AE258FC8u64, 0xB1D219647AE6B31Cu64],
[0x6FCA5F8ED9AEF3BBu64, 0xDE469FBD99A05FE3u64],
[0x25DE7BB9480D5854u64, 0x8AEC23D680043BEEu64],
[0xAF561AA79A10AE6Au64, 0xADA72CCC20054AE9u64],
[0x1B2BA1518094DA04u64, 0xD910F7FF28069DA4u64],
[0x90FB44D2F05D0842u64, 0x87AA9AFF79042286u64],
[0x353A1607AC744A53u64, 0xA99541BF57452B28u64],
[0x42889B8997915CE8u64, 0xD3FA922F2D1675F2u64],
[0x69956135FEBADA11u64, 0x847C9B5D7C2E09B7u64],
[0x43FAB9837E699095u64, 0xA59BC234DB398C25u64],
[0x94F967E45E03F4BBu64, 0xCF02B2C21207EF2Eu64],
[0x1D1BE0EEBAC278F5u64, 0x8161AFB94B44F57Du64],
[0x6462D92A69731732u64, 0xA1BA1BA79E1632DCu64],
[0x7D7B8F7503CFDCFEu64, 0xCA28A291859BBF93u64],
[0x5CDA735244C3D43Eu64, 0xFCB2CB35E702AF78u64],
[0x3A0888136AFA64A7u64, 0x9DEFBF01B061ADABu64],
[0x088AAA1845B8FDD0u64, 0xC56BAEC21C7A1916u64],
[0x8AAD549E57273D45u64, 0xF6C69A72A3989F5Bu64],
[0x36AC54E2F678864Bu64, 0x9A3C2087A63F6399u64],
[0x84576A1BB416A7DDu64, 0xC0CB28A98FCF3C7Fu64],
[0x656D44A2A11C51D5u64, 0xF0FDF2D3F3C30B9Fu64],
[0x9F644AE5A4B1B325u64, 0x969EB7C47859E743u64],
[0x873D5D9F0DDE1FEEu64, 0xBC4665B596706114u64],
[0xA90CB506D155A7EAu64, 0xEB57FF22FC0C7959u64],
[0x09A7F12442D588F2u64, 0x9316FF75DD87CBD8u64],
[0x0C11ED6D538AEB2Fu64, 0xB7DCBF5354E9BECEu64],
[0x8F1668C8A86DA5FAu64, 0xE5D3EF282A242E81u64],
[0xF96E017D694487BCu64, 0x8FA475791A569D10u64],
[0x37C981DCC395A9ACu64, 0xB38D92D760EC4455u64],
[0x85BBE253F47B1417u64, 0xE070F78D3927556Au64],
[0x93956D7478CCEC8Eu64, 0x8C469AB843B89562u64],
[0x387AC8D1970027B2u64, 0xAF58416654A6BABBu64],
[0x06997B05FCC0319Eu64, 0xDB2E51BFE9D0696Au64],
[0x441FECE3BDF81F03u64, 0x88FCF317F22241E2u64],
[0xD527E81CAD7626C3u64, 0xAB3C2FDDEEAAD25Au64],
[0x8A71E223D8D3B074u64, 0xD60B3BD56A5586F1u64],
[0xF6872D5667844E49u64, 0x85C7056562757456u64],
[0xB428F8AC016561DBu64, 0xA738C6BEBB12D16Cu64],
[0xE13336D701BEBA52u64, 0xD106F86E69D785C7u64],
[0xECC0024661173473u64, 0x82A45B450226B39Cu64],
[0x27F002D7F95D0190u64, 0xA34D721642B06084u64],
[0x31EC038DF7B441F4u64, 0xCC20CE9BD35C78A5u64],
[0x7E67047175A15271u64, 0xFF290242C83396CEu64],
[0x0F0062C6E984D386u64, 0x9F79A169BD203E41u64],
[0x52C07B78A3E60868u64, 0xC75809C42C684DD1u64],
[0xA7709A56CCDF8A82u64, 0xF92E0C3537826145u64],
[0x88A66076400BB691u64, 0x9BBCC7A142B17CCBu64],
[0x6ACFF893D00EA435u64, 0xC2ABF989935DDBFEu64],
[0x0583F6B8C4124D43u64, 0xF356F7EBF83552FEu64],
[0xC3727A337A8B704Au64, 0x98165AF37B2153DEu64],
[0x744F18C0592E4C5Cu64, 0xBE1BF1B059E9A8D6u64],
[0x1162DEF06F79DF73u64, 0xEDA2EE1C7064130Cu64],
[0x8ADDCB5645AC2BA8u64, 0x9485D4D1C63E8BE7u64],
[0x6D953E2BD7173692u64, 0xB9A74A0637CE2EE1u64],
[0xC8FA8DB6CCDD0437u64, 0xE8111C87C5C1BA99u64],
[0x1D9C9892400A22A2u64, 0x910AB1D4DB9914A0u64],
[0x2503BEB6D00CAB4Bu64, 0xB54D5E4A127F59C8u64],
[0x2E44AE64840FD61Du64, 0xE2A0B5DC971F303Au64],
[0x5CEAECFED289E5D2u64, 0x8DA471A9DE737E24u64],
[0x7425A83E872C5F47u64, 0xB10D8E1456105DADu64],
[0xD12F124E28F77719u64, 0xDD50F1996B947518u64],
[0x82BD6B70D99AAA6Fu64, 0x8A5296FFE33CC92Fu64],
[0x636CC64D1001550Bu64, 0xACE73CBFDC0BFB7Bu64],
[0x3C47F7E05401AA4Eu64, 0xD8210BEFD30EFA5Au64],
[0x65ACFAEC34810A71u64, 0x8714A775E3E95C78u64],
[0x7F1839A741A14D0Du64, 0xA8D9D1535CE3B396u64],
[0x1EDE48111209A050u64, 0xD31045A8341CA07Cu64],
[0x934AED0AAB460432u64, 0x83EA2B892091E44Du64],
[0xF81DA84D5617853Fu64, 0xA4E4B66B68B65D60u64],
[0x36251260AB9D668Eu64, 0xCE1DE40642E3F4B9u64],
[0xC1D72B7C6B426019u64, 0x80D2AE83E9CE78F3u64],
[0xB24CF65B8612F81Fu64, 0xA1075A24E4421730u64],
[0xDEE033F26797B627u64, 0xC94930AE1D529CFCu64],
[0x169840EF017DA3B1u64, 0xFB9B7CD9A4A7443Cu64],
[0x8E1F289560EE864Eu64, 0x9D412E0806E88AA5u64],
[0xF1A6F2BAB92A27E2u64, 0xC491798A08A2AD4Eu64],
[0xAE10AF696774B1DBu64, 0xF5B5D7EC8ACB58A2u64],
[0xACCA6DA1E0A8EF29u64, 0x9991A6F3D6BF1765u64],
[0x17FD090A58D32AF3u64, 0xBFF610B0CC6EDD3Fu64],
[0xDDFC4B4CEF07F5B0u64, 0xEFF394DCFF8A948Eu64],
[0x4ABDAF101564F98Eu64, 0x95F83D0A1FB69CD9u64],
[0x9D6D1AD41ABE37F1u64, 0xBB764C4CA7A4440Fu64],
[0x84C86189216DC5EDu64, 0xEA53DF5FD18D5513u64],
[0x32FD3CF5B4E49BB4u64, 0x92746B9BE2F8552Cu64],
[0x3FBC8C33221DC2A1u64, 0xB7118682DBB66A77u64],
[0x0FABAF3FEAA5334Au64, 0xE4D5E82392A40515u64],
[0x29CB4D87F2A7400Eu64, 0x8F05B1163BA6832Du64],
[0x743E20E9EF511012u64, 0xB2C71D5BCA9023F8u64],
[0x914DA9246B255416u64, 0xDF78E4B2BD342CF6u64],
[0x1AD089B6C2F7548Eu64, 0x8BAB8EEFB6409C1Au64],
[0xA184AC2473B529B1u64, 0xAE9672ABA3D0C320u64],
[0xC9E5D72D90A2741Eu64, 0xDA3C0F568CC4F3E8u64],
[0x7E2FA67C7A658892u64, 0x8865899617FB1871u64],
[0xDDBB901B98FEEAB7u64, 0xAA7EEBFB9DF9DE8Du64],
[0x552A74227F3EA565u64, 0xD51EA6FA85785631u64],
[0xD53A88958F87275Fu64, 0x8533285C936B35DEu64],
[0x8A892ABAF368F137u64, 0xA67FF273B8460356u64],
[0x2D2B7569B0432D85u64, 0xD01FEF10A657842Cu64],
[0x9C3B29620E29FC73u64, 0x8213F56A67F6B29Bu64],
[0x8349F3BA91B47B8Fu64, 0xA298F2C501F45F42u64],
[0x241C70A936219A73u64, 0xCB3F2F7642717713u64],
[0xED238CD383AA0110u64, 0xFE0EFB53D30DD4D7u64],
[0xF4363804324A40AAu64, 0x9EC95D1463E8A506u64],
[0xB143C6053EDCD0D5u64, 0xC67BB4597CE2CE48u64],
[0xDD94B7868E94050Au64, 0xF81AA16FDC1B81DAu64],
[0xCA7CF2B4191C8326u64, 0x9B10A4E5E9913128u64],
[0xFD1C2F611F63A3F0u64, 0xC1D4CE1F63F57D72u64],
[0xBC633B39673C8CECu64, 0xF24A01A73CF2DCCFu64],
[0xD5BE0503E085D813u64, 0x976E41088617CA01u64],
[0x4B2D8644D8A74E18u64, 0xBD49D14AA79DBC82u64],
[0xDDF8E7D60ED1219Eu64, 0xEC9C459D51852BA2u64],
[0xCABB90E5C942B503u64, 0x93E1AB8252F33B45u64],
[0x3D6A751F3B936243u64, 0xB8DA1662E7B00A17u64],
[0x0CC512670A783AD4u64, 0xE7109BFBA19C0C9Du64],
[0x27FB2B80668B24C5u64, 0x906A617D450187E2u64],
[0xB1F9F660802DEDF6u64, 0xB484F9DC9641E9DAu64],
[0x5E7873F8A0396973u64, 0xE1A63853BBD26451u64],
[0xDB0B487B6423E1E8u64, 0x8D07E33455637EB2u64],
[0x91CE1A9A3D2CDA62u64, 0xB049DC016ABC5E5Fu64],
[0x7641A140CC7810FBu64, 0xDC5C5301C56B75F7u64],
[0xA9E904C87FCB0A9Du64, 0x89B9B3E11B6329BAu64],
[0x546345FA9FBDCD44u64, 0xAC2820D9623BF429u64],
[0xA97C177947AD4095u64, 0xD732290FBACAF133u64],
[0x49ED8EABCCCC485Du64, 0x867F59A9D4BED6C0u64],
[0x5C68F256BFFF5A74u64, 0xA81F301449EE8C70u64],
[0x73832EEC6FFF3111u64, 0xD226FC195C6A2F8Cu64],
];

View File

@@ -0,0 +1,227 @@
// stoftest — exercises lib/strconv/stof.ww (Hare stof.ha port).
// Run with `out/bin/ww run lib/strconv/test/stoftest.ww`. Same
// signalled-then-os.exit(signalled+10) pattern as decimaltest: a
// non-zero exit names the failing @test (1..N → exit 11..N+10).
//
// Ports ref/hare/strconv/stof.ha's @test vectors (stof64 / stof32 /
// stofhex). Comparisons are BIT-level (math.f64bits / f32bits) so a
// sign flip (-0.0 vs 0.0) or a 1-ulp miss fails the row rather than
// silently passing on IEEE `==`. NaN via math.isnan; ±Inf via
// f64frombits(INF_BITS) (ww math has no NAN/INF f32/f64 const — see
// math/floats.ww). Hex extremes (Hare's math::F64_MAX_NORMAL etc.,
// absent in ww math) assert against the IEEE-754 bit patterns directly.
//
// Lives in lib/strconv/test/ so `import strconv` resolves to the
// DIRECTORY (full package: strconv.ww + decimal.ww + stof_data.ww +
// stof.ww), not the strconv.ww FILE — same rationale as decimaltest.
package strconv;
import strconv;
import os;
import math;
let signalled: i32 = 0;
fn fail() void = { os.exit(signalled + 10); };
// ---- unwrap helpers (bit-exact value checks) -------------------------
fn chk64(s: str, b: base, want: f64) bool = {
match (stof64(s, b)) {
case let v: f64 => { return math.f64bits(v) == math.f64bits(want); };
case let e: invalid => { return false; };
case let e: overflow => { return false; };
};
return false;
};
fn chk32(s: str, b: base, want: f32) bool = {
match (stof32(s, b)) {
case let v: f32 => { return math.f32bits(v) == math.f32bits(want); };
case let e: invalid => { return false; };
case let e: overflow => { return false; };
};
return false;
};
fn ovf64(s: str, b: base) bool = {
match (stof64(s, b)) {
case let v: f64 => { return false; };
case let e: invalid => { return false; };
case let e: overflow => { return true; };
};
return false;
};
fn ovf32(s: str, b: base) bool = {
match (stof32(s, b)) {
case let v: f32 => { return false; };
case let e: invalid => { return false; };
case let e: overflow => { return true; };
};
return false;
};
// inv64 — the invalid byte-index, or -1 if not invalid.
fn inv64(s: str) i32 = {
match (stof64(s, base.DEC)) {
case let v: f64 => { return -1; };
case let e: invalid => { return (e: i32); };
case let e: overflow => { return -1; };
};
return -1;
};
fn inv32(s: str) i32 = {
match (stof32(s, base.DEC)) {
case let v: f32 => { return -1; };
case let e: invalid => { return (e: i32); };
case let e: overflow => { return -1; };
};
return -1;
};
fn nan64(s: str) bool = {
match (stof64(s, base.DEC)) {
case let v: f64 => { return math.isnan(v); };
case let e: invalid => { return false; };
case let e: overflow => { return false; };
};
return false;
};
fn nan32(s: str) bool = {
match (stof32(s, base.DEC)) {
case let v: f32 => { return math.isnan((v: f64)); };
case let e: invalid => { return false; };
case let e: overflow => { return false; };
};
return false;
};
// ---- stof64 ----------------------------------------------------------
// ref/hare/strconv/stof.ha:530.
@test fn stof64_dec() void = {
let inf: f64 = math.f64frombits(math.INF_BITS);
let ninf: f64 = math.f64frombits(0xFFF0000000000000u64);
let nzero: f64 = math.f64frombits(1u64 << 63u64); // -0.0 (1<<63 dodges the I64_MIN-literal emit bug #144)
let subn: f64 = math.f64frombits(0x0000000000000001u64); // 5e-324
if (!chk64("0", base.DEC, 0.0)) { fail(); };
if (!chk64("200", base.DEC, 200.0)) { fail(); };
if (!chk64("12345", base.DEC, 12345.0)) { fail(); };
if (!chk64("+112233445566778899", base.DEC, 1.122334455667789e17)) { fail(); };
if (!chk64("3.14", base.DEC, 3.14)) { fail(); };
if (!chk64("2.99792458E+8", base.DEC, 299792458.0)) { fail(); };
if (!chk64("6.022e23", base.DEC, 6.022e23)) { fail(); };
if (!ovf64("1e310", base.DEC)) { fail(); };
if (!chk64("9007199254740991", base.DEC, 9007199254740991.0)) { fail(); };
if (!chk64("90071992547409915", base.DEC, 90071992547409920.0)) { fail(); };
if (!chk64("90071992547409925", base.DEC, 90071992547409920.0)) { fail(); };
if (!chk64("2.2250738585072014e-308", base.DEC, 2.2250738585072014e-308)) { fail(); };
if (!chk64("-1e-324", base.DEC, nzero)) { fail(); };
if (!chk64("5e-324", base.DEC, subn)) { fail(); };
if (inv64("") != 0) { fail(); };
if (inv64("0ZO") != 1) { fail(); };
if (inv64("1.23ezz") != 5) { fail(); };
if (!chk64("Infinity", base.DEC, inf)) { fail(); };
if (!chk64("+Infinity", base.DEC, inf)) { fail(); };
if (!chk64("-Infinity", base.DEC, ninf)) { fail(); };
if (!chk64("infinity", base.DEC, inf)) { fail(); };
if (!chk64("inFinIty", base.DEC, inf)) { fail(); };
if (!chk64("-infinity", base.DEC, ninf)) { fail(); };
if (!chk64("-infiNity", base.DEC, ninf)) { fail(); };
if (!nan64("NaN")) { fail(); };
if (!nan64("nan")) { fail(); };
if (!nan64("naN")) { fail(); };
};
// ---- stof32 ----------------------------------------------------------
// ref/hare/strconv/stof.ha:560.
@test fn stof32_dec() void = {
let inf: f32 = math.f32frombits(0x7F800000u32);
let ninf: f32 = math.f32frombits(0xFF800000u32);
let nzero: f32 = math.f32frombits(0x80000000u32); // -0.0
let subn: f32 = math.f32frombits(0x00000001u32); // 1e-45
if (!chk32("0", base.DEC, 0.0f32)) { fail(); };
if (!chk32("1e10", base.DEC, 1.0e10f32)) { fail(); };
if (!chk32("299792458", base.DEC, 299792458.0f32)) { fail(); };
if (!chk32("6.022e23", base.DEC, 6.022e23f32)) { fail(); };
if (!ovf32("1e40", base.DEC)) { fail(); };
if (!chk32("16777215", base.DEC, 16777215.0f32)) { fail(); };
if (!chk32("167772155", base.DEC, 167772160.0f32)) { fail(); };
if (!chk32("167772145", base.DEC, 167772140.0f32)) { fail(); };
if (!chk32("6.62607015e-34", base.DEC, 6.62607015e-34f32)) { fail(); };
if (!chk32("1.1754944e-38", base.DEC, 1.1754944e-38f32)) { fail(); };
if (!chk32("-1e-50", base.DEC, nzero)) { fail(); };
if (!chk32("1e-45", base.DEC, subn)) { fail(); };
if (inv32("") != 0) { fail(); };
if (inv32("0ZO") != 1) { fail(); };
if (inv32("1.23e-zz") != 6) { fail(); };
if (!chk32("Infinity", base.DEC, inf)) { fail(); };
if (!chk32("+Infinity", base.DEC, inf)) { fail(); };
if (!chk32("-Infinity", base.DEC, ninf)) { fail(); };
if (!chk32("infinity", base.DEC, inf)) { fail(); };
if (!chk32("inFinIty", base.DEC, inf)) { fail(); };
if (!chk32("-infinity", base.DEC, ninf)) { fail(); };
if (!chk32("-infiniTy", base.DEC, ninf)) { fail(); };
if (!nan32("NaN")) { fail(); };
if (!nan32("nan")) { fail(); };
if (!nan32("naN")) { fail(); };
if (!chk32("9.19100241453305036800e+20", base.DEC, 9.19100241453305036800e+20f32)) { fail(); };
};
// ---- stofhex ---------------------------------------------------------
// ref/hare/strconv/stof.ha:590. Hex-float surface-form literals (0x1.fp-2,
// math::F64_MAX_NORMAL, …) are spelled as IEEE-754 bit patterns since ww
// has no hex-float literal lexer / no F*_MAX_NORMAL math consts.
@test fn stof64_hex() void = {
if (!chk64("0p0", base.HEX, 0.0)) { fail(); };
if (!chk64("1p0", base.HEX, 1.0)) { fail(); };
if (!chk64("-1p0", base.HEX_LOWER, -1.0)) { fail(); };
// 0x1.fp-2 = 1.9375 * 2^-2 = 0.484375 (exact).
if (!chk64("1.fp-2", base.HEX, 0.484375)) { fail(); };
// F64_MAX_NORMAL.
if (!chk64("1.fffffffffffffp+1023", base.HEX,
math.f64frombits(0x7FEFFFFFFFFFFFFFu64))) { fail(); };
// F64_MIN_NORMAL.
if (!chk64("1.0000000000000p-1022", base.HEX,
math.f64frombits(0x0010000000000000u64))) { fail(); };
// F64_MIN_SUBNORMAL.
if (!chk64("0.0000000000001p-1022", base.HEX,
math.f64frombits(0x0000000000000001u64))) { fail(); };
if (!ovf64("1p+1024", base.HEX)) { fail(); };
if (!chk64("0.00000000000001p-1022", base.HEX, 0.0)) { fail(); };
};
@test fn stof32_hex() void = {
if (!chk32("0p0", base.HEX, 0.0f32)) { fail(); };
if (!chk32("1p0", base.HEX, 1.0f32)) { fail(); };
if (!chk32("-1p0", base.HEX, -1.0f32)) { fail(); };
if (!chk32("1.fp-2", base.HEX, 0.484375f32)) { fail(); };
// F32_MAX_NORMAL.
if (!chk32("1.fffffd586b834p+127", base.HEX,
math.f32frombits(0x7F7FFFFFu32))) { fail(); };
// F32_MIN_NORMAL.
if (!chk32("1.0p-126", base.HEX, math.f32frombits(0x00800000u32))) { fail(); };
// F32_MIN_SUBNORMAL.
if (!chk32("1.6p-150", base.HEX, math.f32frombits(0x00000001u32))) { fail(); };
if (!ovf32("1.0p+128", base.HEX)) { fail(); };
if (!chk32("1.0p-151", base.HEX, 0.0f32)) { fail(); };
};
export fn main() i32 = {
signalled = 1; stof64_dec();
signalled = 2; stof32_dec();
signalled = 3; stof64_hex();
signalled = 4; stof32_hex();
return 0;
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

55
test/wcc/909_stof_run.c Normal file
View File

@@ -0,0 +1,55 @@
/*
* 909_stof_run — execute the lib/strconv/test/stoftest fixture under the
* C-side `ww run` driver and assert exit 0.
*
* Same thin-wrapper shape as 922_decimal_run: stoftest.ww carries its own
* `export fn main()` that drives the @test fns (stof64/stof32 DEC + hex
* vectors, bit-exact) and signals which case failed via the exit code
* (signalled + 10, so cases 1..4 → exit 11..14).
*
* The fixture lives in lib/strconv/test/ (not lib/strconv/) so
* `import strconv` resolves to the lib/strconv DIRECTORY (full package:
* strconv.ww + decimal.ww + stof_data.ww + stof.ww), not the strconv.ww
* FILE — same rationale as 922_decimal_run.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
static int
runwait(const char *cmd)
{
int rc = system(cmd);
if (rc == -1) return -1;
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
return 1;
}
int
main(void)
{
const char *bin = getenv("BIN");
if (!bin) bin = "out/bin";
char absbin[1024];
if (bin[0] != '/') {
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin);
bin = absbin;
}
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
const char *src = "lib/strconv/test/stoftest.ww";
char path[1024], cmd[2048];
snprintf(path, sizeof path, "%s/%s", cwd, src);
snprintf(cmd, sizeof cmd, "%s/ww run %s", bin, path);
int rc = runwait(cmd);
if (rc != 0) {
fprintf(stderr, "stof_run FAIL: %s exited %d\n", src, rc);
return 1;
}
printf("stof_run: %s ok\n", src);
return 0;
}