// 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. Parens around &n are load-bearing: ww's `:` // cast binds tighter than unary `&`, so Hare's `*(&n: *u64)` would parse // as `*(&(n: *u64))`; `(&n): *u64` reinterprets the address as intended. export fn f64bits(n: f64) u64 = { return *((&n): *u64); }; // Returns f64 with the given binary representation. // ref/hare/math/floats.ha:11 export fn f64frombits(n: u64) f64 = { return *((&n): *f64); }; // 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)); };