diff --git a/lib/math/floats.ww b/lib/math/floats.ww new file mode 100644 index 00000000..d6bd2367 --- /dev/null +++ b/lib/math/floats.ww @@ -0,0 +1,104 @@ +// floats — f64 classification, sign, and bit-reinterpret core. Ported +// from ref/hare/math/floats.ha (fold-1: the minimal classify/sign/bits +// surface). f32 variants, NAN/INF + magnitude consts, and +// frexp/ldexp/normalize/modfrac/nextafter are deferred to a later fold. + +package math; + +// Returns the binary representation of the given f64. +// ref/hare/math/floats.ha:5 +export fn f64bits(n: f64) u64 = { + let p: *u64 = (&n): *u64; + return *p; +}; + +// Returns f64 with the given binary representation. +// ref/hare/math/floats.ha:11 +export fn f64frombits(n: u64) f64 = { + let p: *f64 = (&n): *f64; + return *p; +}; + +// 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 +// through unify_arith, which rejects mixed operand types (cmd/wcc/ +// check.c:769). The bit-structure consts are used only as u64 shift +// amounts and mask widths, so they are typed u64 here — the closest +// stand-in for Hare's untyped-int adapt at those use sites. + +// The number of bits in the significand of the binary representation of f64. +export def F64_MANTISSA_BITS: u64 = 52; + +// The number of bits in the exponent of the binary representation of f64. +export def F64_EXPONENT_BITS: u64 = 11; + +// The bias of the exponent of the binary representation of f64. Subtract this +// from the exponent in the binary representation to get the actual exponent. +export def F64_EXPONENT_BIAS: u64 = 1023; + +// Mask with each bit of an f64's mantissa set. +// ref/hare/math/floats.ha:37 +export def F64_MANTISSA_MASK: u64 = (1 << F64_MANTISSA_BITS) - 1; + +// Mask with each bit of an f64's exponent set. +// ref/hare/math/floats.ha:40 +export def F64_EXPONENT_MASK: u64 = (1 << F64_EXPONENT_BITS) - 1; + +// The mask that gets an f64's sign. +// ref/hare/math/floats.ha:75 +def F64_SIGN_MASK: u64 = 1u64 << 63; + +// 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). +export fn isnan(n: f64) bool = { + return n != n; +}; + +// Returns true if the given floating-point number is infinite. +// ref/hare/math/floats.ha:147 +export fn isinf(n: f64) bool = { + const bits = f64bits(n); + const mant = bits & F64_MANTISSA_MASK; + const exp = bits >> F64_MANTISSA_BITS & F64_EXPONENT_MASK; + return exp == F64_EXPONENT_MASK && mant == 0; +}; + +// Returns the absolute value of f64 n. +// ref/hare/math/floats.ha:195 +export fn absf64(n: f64) f64 = { + if (isnan(n)) { + return n; + }; + return f64frombits(f64bits(n) & ~F64_SIGN_MASK); +}; + +// Returns 1 if x is positive and -1 if x is negative. Note that zero is also +// signed. +// ref/hare/math/floats.ha:212 +export fn signf64(x: f64) i64 = { + if (f64bits(x) & F64_SIGN_MASK == 0) { + return 1i64; + } else { + return -1i64; + }; +}; + +// Returns whether or not x is positive. +// ref/hare/math/floats.ha:231 +export fn ispositivef64(x: f64) bool = { + return signf64(x) == 1i64; +}; + +// Returns whether or not x is negative. +// ref/hare/math/floats.ha:237 +export fn isnegativef64(x: f64) bool = { + return signf64(x) == -1i64; +}; + +// Returns x, but with the sign of y. +// ref/hare/math/floats.ha:243 +export fn copysignf64(x: f64, y: f64) f64 = { + return f64frombits((f64bits(x) & ~F64_SIGN_MASK) | + (f64bits(y) & F64_SIGN_MASK)); +};