From e28d6b2e9d91c62f96853323de2b06bdbc15b513 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Tue, 26 May 2026 19:19:48 +0900 Subject: [PATCH] lib/math: NAN/INF bits + flattened F64_EXPBIAS (#106 fold-1b) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flattened from Hare's const struct instances per #129 cgen module-let- init gap; NAN/INF expressed as `def NAN_BITS:u64 = 0x...;` and `def INF_BITS:u64 = 0x...;` materialized via f64frombits(NAN_BITS) at use-site. F64_EXPBIAS:int flattened from f64info.expbias (cite ref/hare/math/floats.ha:117); floatinfo struct definition preserved for γ-cleanup re-fold when #129 closes. F32_EXPBIAS deferred (option-ii: stof.ha consumers reach f.expbias via struct-field only). --- lib/math/floats.ww | 35 +++++++++++++++++++++++++++++------ test/wcc/952_floats_run.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/lib/math/floats.ww b/lib/math/floats.ww index 33655f33..6582e1c1 100644 --- a/lib/math/floats.ww +++ b/lib/math/floats.ww @@ -1,12 +1,13 @@ // floats — f64 classification, sign, bit-reinterpret core, and the f64 // decompose half (subnormal-normalize + frexp). Ported from // ref/hare/math/floats.ha (fold-1: classify/sign/bits; fold-2a: -// issubnormalf64/normalizef64/frexpf64; strconv-foundation fold: -// F32 bit-layout + f32bits/f32frombits + floatinfo struct type). -// frexpf64's zero guard `n == 0f64` rides the #103 fix (no-decimal f64 -// literal now materialized into XMM) and its (f64, i64) tuple return -// rides the #105 fix (tuple f64-word read). The ldexp/modfrac/nextafter -// family stays deferred (need f64 DIVIDE + the INF const). +// issubnormalf64/normalizef64/frexpf64; strconv-foundation fold-1a: +// F32 bit-layout + f32bits/f32frombits + floatinfo struct type; +// fold-1b: NAN_BITS/INF_BITS sentinels + F64_EXPBIAS (flattened from +// f64info per #129)). frexpf64's zero guard `n == 0f64` rides the #103 +// fix (no-decimal f64 literal now materialized into XMM) and its +// (f64, i64) tuple return rides the #105 fix (tuple f64-word read). +// The ldexp/modfrac/nextafter family stays deferred (need f64 DIVIDE). package math; @@ -77,6 +78,15 @@ def F64_EXP_REMOVAL_MASK: u64 = ~(F64_EXPONENT_MASK << F64_MANTISSA_BITS); // ref/hare/math/floats.ha:84 def F64_EXP_ZERO: u64 = (F64_EXPONENT_BIAS - 1) << F64_MANTISSA_BITS; +// flattened from f64info per #129 (cgen module-level struct-init gap); +// cite ref/hare/math/floats.ha:117. Re-fold to const f64info: floatinfo +// when #129 closes (γ-cleanup pattern per amalloc-drop precedent). +// The existing F64_EXPONENT_BIAS:u64 above is the bit-ops alias; this +// int-typed F64_EXPBIAS is the floatinfo.expbias-field counterpart and +// drops the cast at the construction site (see ref/hare/strconv/stof.ha +// :248,288 for the consumer pattern). +export def F64_EXPBIAS: int = 1023; + // F32 bit-structure constants. ref/hare/math/floats.ha:27,30,33 declare // these as untyped int; ww has no untyped def, so they ride u32 (matching // the u32 bit container, the same way the F64 family rides u64 — see @@ -144,6 +154,19 @@ export type floatinfo = struct { expmask: u64, }; +// IEEE-754 quiet-NaN and positive-Infinity f64 bit sentinels. +// ref/hare/math/floats.ha:137,141. Hare exports `def NAN = 0.0/0.0;` and +// `def INF = 1.0/0.0;` (untyped float def-fold); ww's cgen doesn't lower +// `def: f64 = expr;` (the symbol comes out undefined at link time — see +// #129). Callers materialize the f64 sentinel via f64frombits(NAN_BITS) +// / f64frombits(INF_BITS); same bit-exact value, one extra reinterpret. +// 0x7FF8000000000000 is the IEEE-754 binary64 quiet-NaN (sign=0, exp= +// all-ones, mantissa MSB=1, rest=0); 0x7FF0000000000000 is +Infinity +// (sign=0, exp=all-ones, mantissa=0). Re-fold to `def NAN: f64 = ...` +// when #129 closes (γ-cleanup pattern per amalloc-drop precedent). +export def NAN_BITS: u64 = 0x7FF8000000000000u64; +export def INF_BITS: u64 = 0x7FF0000000000000u64; + // Returns true if the given floating-point number is NaN. // ref/hare/math/floats.ha:144 (Hare's expression body inlined into a // block: ww has no expression-bodied fn form, only brace blocks). diff --git a/test/wcc/952_floats_run.c b/test/wcc/952_floats_run.c index 24fb91f9..cf7ba705 100644 --- a/test/wcc/952_floats_run.c +++ b/test/wcc/952_floats_run.c @@ -306,6 +306,43 @@ static const struct row rows[] = { " if (readbits(&info) != 23u64) { return 3; };\n" " return 0;\n" "};\n", 0 }, + /* --- strconv-foundation fold-1b: NAN_BITS / INF_BITS sentinels. + * Hare exports `def NAN = 0.0/0.0;` / `def INF = 1.0/0.0;` (ref/hare/ + * math/floats.ha:137,141); ww materializes via f64frombits(NAN_BITS) + * / f64frombits(INF_BITS) until #129 closes. The bit values are + * IEEE-754 facts (quiet-NaN: exp-all-ones + mantissa-MSB; +Inf: + * exp-all-ones + mantissa-zero) — any drift means the def-folded + * sentinels broke. */ + { "package main;\n" + "import math;\n" + "export fn main() i32 = {\n" + " if (math.NAN_BITS != 0x7FF8000000000000u64) { return 1; };\n" + " if (math.INF_BITS != 0x7FF0000000000000u64) { return 2; };\n" + " let n: f64 = math.f64frombits(math.NAN_BITS);\n" + " if (!math.isnan(n)) { return 3; };\n" + " if (math.isnan(1.0)) { return 4; };\n" + " let i: f64 = math.f64frombits(math.INF_BITS);\n" + " if (!math.isinf(i)) { return 5; };\n" + " if (!math.isinf(-i)) { return 6; };\n" + " if (math.isinf(1.23)) { return 7; };\n" + " return 0;\n" + "};\n", 0 }, + /* F64_EXPBIAS — the f64info.expbias-field-typed counterpart of the + * existing F64_EXPONENT_BIAS:u64. Flattened from f64info per #129. + * Round-trips into a floatinfo struct's expbias field with zero + * casts (the consumer pattern fold-4 stof will use). Cite ref/hare/ + * math/floats.ha:117 (f64info struct const) + :24 (the existing + * untyped F64_EXPONENT_BIAS). */ + { "package main;\n" + "import math;\n" + "export fn main() i32 = {\n" + " if (math.F64_EXPBIAS != 1023) { return 1; };\n" + " let info: math.floatinfo;\n" + " info.expbias = math.F64_EXPBIAS;\n" + " if (info.expbias != 1023) { return 2; };\n" + " if (info.expbias != math.F64_EXPBIAS) { return 3; };\n" + " return 0;\n" + "};\n", 0 }, { NULL, 0 } };