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:
@@ -1,11 +1,12 @@
|
|||||||
// floats — f64 classification, sign, bit-reinterpret core, and the f64
|
// floats — f64 classification, sign, bit-reinterpret core, and the f64
|
||||||
// decompose half (subnormal-normalize + frexp). Ported from
|
// decompose half (subnormal-normalize + frexp). Ported from
|
||||||
// ref/hare/math/floats.ha (fold-1: classify/sign/bits; fold-2a:
|
// ref/hare/math/floats.ha (fold-1: classify/sign/bits; fold-2a:
|
||||||
// issubnormalf64/normalizef64/frexpf64). frexpf64's zero guard `n == 0f64`
|
// issubnormalf64/normalizef64/frexpf64; strconv-foundation fold:
|
||||||
// rides the #103 fix (no-decimal f64 literal now materialized into XMM)
|
// F32 bit-layout + f32bits/f32frombits + floatinfo struct type).
|
||||||
// and its (f64, i64) tuple return rides the #105 fix (tuple f64-word read).
|
// frexpf64's zero guard `n == 0f64` rides the #103 fix (no-decimal f64
|
||||||
// f32 variants stay deferred (#104 blocks the f32 call-arg narrowing), as
|
// literal now materialized into XMM) and its (f64, i64) tuple return
|
||||||
// do the ldexp/modfrac/nextafter family (need f64 DIVIDE + the INF const).
|
// rides the #105 fix (tuple f64-word read). The ldexp/modfrac/nextafter
|
||||||
|
// family stays deferred (need f64 DIVIDE + the INF const).
|
||||||
|
|
||||||
package math;
|
package math;
|
||||||
|
|
||||||
@@ -17,12 +18,24 @@ export fn f64bits(n: f64) u64 = {
|
|||||||
return *((&n): *u64);
|
return *((&n): *u64);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Returns the binary representation of the given f32.
|
||||||
|
// ref/hare/math/floats.ha:8
|
||||||
|
export fn f32bits(n: f32) u32 = {
|
||||||
|
return *((&n): *u32);
|
||||||
|
};
|
||||||
|
|
||||||
// Returns f64 with the given binary representation.
|
// Returns f64 with the given binary representation.
|
||||||
// ref/hare/math/floats.ha:11
|
// ref/hare/math/floats.ha:11
|
||||||
export fn f64frombits(n: u64) f64 = {
|
export fn f64frombits(n: u64) f64 = {
|
||||||
return *((&n): *f64);
|
return *((&n): *f64);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Returns f32 with the given binary representation.
|
||||||
|
// ref/hare/math/floats.ha:14
|
||||||
|
export fn f32frombits(n: u32) f32 = {
|
||||||
|
return *((&n): *f32);
|
||||||
|
};
|
||||||
|
|
||||||
// ref/hare/math/floats.ha:17,20,23 declare these as untyped int. ww has
|
// ref/hare/math/floats.ha:17,20,23 declare these as untyped int. ww has
|
||||||
// no untyped def (every def carries a type) and routes shift/bitwise
|
// no untyped def (every def carries a type) and routes shift/bitwise
|
||||||
// through unify_arith, which rejects mixed operand types (cmd/wcc/
|
// through unify_arith, which rejects mixed operand types (cmd/wcc/
|
||||||
@@ -64,6 +77,73 @@ def F64_EXP_REMOVAL_MASK: u64 = ~(F64_EXPONENT_MASK << F64_MANTISSA_BITS);
|
|||||||
// ref/hare/math/floats.ha:84
|
// ref/hare/math/floats.ha:84
|
||||||
def F64_EXP_ZERO: u64 = (F64_EXPONENT_BIAS - 1) << F64_MANTISSA_BITS;
|
def F64_EXP_ZERO: u64 = (F64_EXPONENT_BIAS - 1) << F64_MANTISSA_BITS;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// the note above F64_MANTISSA_BITS).
|
||||||
|
|
||||||
|
// The number of bits in the significand of the binary representation of f32.
|
||||||
|
// ref/hare/math/floats.ha:27
|
||||||
|
export def F32_MANTISSA_BITS: u32 = 23u32;
|
||||||
|
|
||||||
|
// The number of bits in the exponent of the binary representation of f32.
|
||||||
|
// ref/hare/math/floats.ha:30
|
||||||
|
export def F32_EXPONENT_BITS: u32 = 8u32;
|
||||||
|
|
||||||
|
// The bias of the exponent of the binary representation of f32. Subtract this
|
||||||
|
// from the exponent in the binary representation to get the actual exponent.
|
||||||
|
// ref/hare/math/floats.ha:33
|
||||||
|
export def F32_EXPONENT_BIAS: u32 = 127u32;
|
||||||
|
|
||||||
|
// Mask with each bit of an f32's mantissa set.
|
||||||
|
// ref/hare/math/floats.ha:43
|
||||||
|
export def F32_MANTISSA_MASK: u32 = (1u32 << F32_MANTISSA_BITS) - 1u32;
|
||||||
|
|
||||||
|
// Mask with each bit of an f32's exponent set.
|
||||||
|
// ref/hare/math/floats.ha:46
|
||||||
|
export def F32_EXPONENT_MASK: u32 = (1u32 << F32_EXPONENT_BITS) - 1u32;
|
||||||
|
|
||||||
|
// The mask that gets an f32's sign.
|
||||||
|
// ref/hare/math/floats.ha:87
|
||||||
|
def F32_SIGN_MASK: u32 = 1u32 << 31;
|
||||||
|
|
||||||
|
// Mask that clears an f32's exponent field, keeping sign + mantissa.
|
||||||
|
// ref/hare/math/floats.ha:92. Hare hardcodes the binary literal (its
|
||||||
|
// lexer can't const-fold the expression); ww's #88 def-const-fold can,
|
||||||
|
// so the readable form is kept (same call as F64_EXP_REMOVAL_MASK).
|
||||||
|
def F32_EXP_REMOVAL_MASK: u32 = ~(F32_EXPONENT_MASK << F32_MANTISSA_BITS);
|
||||||
|
|
||||||
|
// The f32 bit pattern whose exponent field evaluates to zero (0.5 scale).
|
||||||
|
// ref/hare/math/floats.ha:95
|
||||||
|
def F32_EXP_ZERO: u32 = (F32_EXPONENT_BIAS - 1u32) << F32_MANTISSA_BITS;
|
||||||
|
|
||||||
|
// floatinfo — IEEE-754 shape parameters for a binary float type, passed
|
||||||
|
// to width-generic helpers in strconv (eisel_lemire, floatbits, hex_to_bits,
|
||||||
|
// mkfloat). ref/hare/math/floats.ha:101. Hare's `int` maps to ww's `int`
|
||||||
|
// (machine word, 8B; project_int_machine_word_derived_limits), so the
|
||||||
|
// expbias field stays `int` — that keeps the fold-4 stof port byte-for-byte
|
||||||
|
// against ref/hare/strconv/stof.ha:248,288 (`let e: int = 0` arithmetic
|
||||||
|
// against `f.expbias` of the same type, no cast at use site).
|
||||||
|
//
|
||||||
|
// The companion `f64info` / `f32info` module-scope instances Hare exports
|
||||||
|
// (ref/hare/math/floats.ha:117,126) are DEFERRED — ww's cgen doesn't
|
||||||
|
// lower module-level struct lets-with-initializer (the symbol comes out
|
||||||
|
// undefined at link time). Callers in the fold-4 stof port construct a
|
||||||
|
// stack-local `floatinfo { ... }` and pass `&info` until that gap closes.
|
||||||
|
// Repro logged with team lead.
|
||||||
|
export type floatinfo = struct {
|
||||||
|
// Bits in significand.
|
||||||
|
mantbits: u64,
|
||||||
|
// Bits in exponent.
|
||||||
|
expbits: u64,
|
||||||
|
// Bias of exponent.
|
||||||
|
expbias: int,
|
||||||
|
// Mask for mantissa.
|
||||||
|
mantmask: u64,
|
||||||
|
// Mask for exponent.
|
||||||
|
expmask: u64,
|
||||||
|
};
|
||||||
|
|
||||||
// Returns true if the given floating-point number is NaN.
|
// Returns true if the given floating-point number is NaN.
|
||||||
// ref/hare/math/floats.ha:144 (Hare's expression body inlined into a
|
// ref/hare/math/floats.ha:144 (Hare's expression body inlined into a
|
||||||
// block: ww has no expression-bodied fn form, only brace blocks).
|
// block: ww has no expression-bodied fn form, only brace blocks).
|
||||||
|
|||||||
@@ -221,6 +221,91 @@ static const struct row rows[] = {
|
|||||||
" const r = math.frexpf64(1024.0);\n"
|
" const r = math.frexpf64(1024.0);\n"
|
||||||
" return r.1: i32;\n"
|
" return r.1: i32;\n"
|
||||||
"};\n", 11 },
|
"};\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 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user