lib/math: F32 family + f32bits/f32frombits + floatinfo struct (#106 fold-1a)

F32 width consts + bit converters mirror existing F64 family; floatinfo
struct definition (instances deferred to fold-1b per #129 cgen module-
let-init gap). Cite ref/hare/math/floats.ha; expbias: int per Drew.
This commit is contained in:
2026-05-26 19:10:02 +09:00
parent 0a2747ce5b
commit e9620953a0
2 changed files with 170 additions and 5 deletions

View File

@@ -221,6 +221,91 @@ static const struct row rows[] = {
" const r = math.frexpf64(1024.0);\n"
" return r.1: i32;\n"
"};\n", 11 },
/* --- strconv-foundation fold-1: F32 width constants. Mirror
* ref/hare/math/floats.ha:27,30,33,43,46. The shape values (23/8/
* 127, 0x7FFFFF, 0xFF) are facts of IEEE 754 binary32 — any drift
* here means F32_* def-folding broke. */
{ "package main;\n"
"import math;\n"
"export fn main() i32 = {\n"
" if (math.F32_MANTISSA_BITS != 23u32) { return 1; };\n"
" if (math.F32_EXPONENT_BITS != 8u32) { return 2; };\n"
" if (math.F32_EXPONENT_BIAS != 127u32) { return 3; };\n"
" if (math.F32_MANTISSA_MASK != 0x7FFFFFu32) { return 4; };\n"
" if (math.F32_EXPONENT_MASK != 0xFFu32) { return 5; };\n"
" return 0;\n"
"};\n", 0 },
/* f32bits / f32frombits round-trip. Mirror
* ref/hare/math/floats.ha:8,14 + ref/hare/math/+test/floats_test.ha:4
* (the f32 leg). 1.0f32 -> 0x3F800000, 2.0f32 -> 0x40000000,
* -1.0f32 -> 0xBF800000, 0.0f32 -> 0u32. Rides the f32-literal
* materialise path (#104 fold-1) and the f32 ptr-deref read/write. */
{ "package main;\n"
"import math;\n"
"export fn main() i32 = {\n"
" if (math.f32bits(1.0f32) != 0x3F800000u32) { return 1; };\n"
" if (math.f32bits(2.0f32) != 0x40000000u32) { return 2; };\n"
" if (math.f32bits(-1.0f32) != 0xBF800000u32) { return 3; };\n"
" if (math.f32bits(0.0f32) != 0u32) { return 4; };\n"
" if (math.f32frombits(0x3F800000u32) != 1.0f32) { return 5; };\n"
" if (math.f32frombits(0x40000000u32) != 2.0f32) { return 6; };\n"
" if (math.f32frombits(0xBF800000u32) != -1.0f32) { return 7; };\n"
" if (math.f32frombits(0u32) != 0.0f32) { return 8; };\n"
" let v: f32 = 123456.0f32;\n"
" if (math.f32frombits(math.f32bits(v)) != v) { return 9; };\n"
" return 0;\n"
"};\n", 0 },
/* f32bits value propagation: bit pattern 0x42280000 == 42.0f32; the
* u32 cast to i32 propagates as 42. */
{ "package main;\n"
"import math;\n"
"export fn main() i32 = {\n"
" return math.f32frombits(0x42280000u32): i32;\n"
"};\n", 42 },
/* floatinfo struct: f64-shape instance, address-of must round-trip
* through a *floatinfo pointer parameter — that's the call shape
* stof's eisel_lemire (`f: *floatinfo`) uses in fold-4. Mirrors
* ref/hare/math/floats.ha:103. Stack-local because module-level
* struct lets-with-init don't lower yet (gap reported with lead).
* Field assignments rather than a struct literal: ww's N_DOT-qualified
* `math.floatinfo { ... }` literal trips the cross-module resolver
* (#16/#17, task list #12). */
{ "package main;\n"
"import math;\n"
"fn readbits(p: *math.floatinfo) u64 = { return p.mantbits; };\n"
"export fn main() i32 = {\n"
" let info: math.floatinfo;\n"
" info.mantbits = 52u64;\n"
" info.expbits = 11u64;\n"
" info.expbias = 1023;\n"
" info.mantmask = 0xFFFFFFFFFFFFFu64;\n"
" info.expmask = 0x7FFu64;\n"
" if (info.mantbits != 52u64) { return 1; };\n"
" if (info.expbits != 11u64) { return 2; };\n"
" if (info.expbias != 1023) { return 3; };\n"
" if (info.mantmask != 0xFFFFFFFFFFFFFu64) { return 4; };\n"
" if (info.expmask != 0x7FFu64) { return 5; };\n"
" if (readbits(&info) != 52u64) { return 6; };\n"
" return 0;\n"
"};\n", 0 },
/* floatinfo f32-shape instance. Same fold as above; verifies the
* struct type is width-agnostic (Hare exports both f64info and
* f32info, ref/hare/math/floats.ha:117,126). */
{ "package main;\n"
"import math;\n"
"fn readbits(p: *math.floatinfo) u64 = { return p.mantbits; };\n"
"export fn main() i32 = {\n"
" let info: math.floatinfo;\n"
" info.mantbits = 23u64;\n"
" info.expbits = 8u64;\n"
" info.expbias = 127;\n"
" info.mantmask = 0x7FFFFFu64;\n"
" info.expmask = 0xFFu64;\n"
" if (info.mantbits != 23u64) { return 1; };\n"
" if (info.expbias != 127) { return 2; };\n"
" if (readbits(&info) != 23u64) { return 3; };\n"
" return 0;\n"
"};\n", 0 },
{ NULL, 0 }
};