|
// Ported from musl, which is MIT licensed: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // // https://git.musl-libc.org/cgit/musl/tree/src/math/frexpl.c // https://git.musl-libc.org/cgit/musl/tree/src/math/frexpf.c // https://git.musl-libc.org/cgit/musl/tree/src/math/frexp.c const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; |
Frexp() |
pub fn Frexp(comptime T: type) type { return struct { significand: T, exponent: i32, }; } |
frexp() Breaks x into a normalized fraction and an integral power of two. f == frac * 2^exp, with |frac| in the interval [0.5, 1). |
pub fn frexp(x: anytype) Frexp(@TypeOf(x)) { const T = @TypeOf(x); return switch (T) { f32 => frexp32(x), f64 => frexp64(x), f128 => frexp128(x), else => @compileError("frexp not implemented for " ++ @typeName(T)), }; } // TODO: unify all these implementations using generics fn frexp32(x: f32) Frexp(f32) { var result: Frexp(f32) = undefined; var y = @as(u32, @bitCast(x)); const e = @as(i32, @intCast(y >> 23)) & 0xFF; if (e == 0) { if (x != 0) { // subnormal result = frexp32(x * 0x1.0p64); result.exponent -= 64; } else { // frexp(+-0) = (+-0, 0) result.significand = x; result.exponent = 0; } return result; } else if (e == 0xFF) { // frexp(nan) = (nan, undefined) result.significand = x; result.exponent = undefined; // frexp(+-inf) = (+-inf, 0) if (math.isInf(x)) { result.exponent = 0; } return result; } result.exponent = e - 0x7E; y &= 0x807FFFFF; y |= 0x3F000000; result.significand = @as(f32, @bitCast(y)); return result; } fn frexp64(x: f64) Frexp(f64) { var result: Frexp(f64) = undefined; var y = @as(u64, @bitCast(x)); const e = @as(i32, @intCast(y >> 52)) & 0x7FF; if (e == 0) { if (x != 0) { // subnormal result = frexp64(x * 0x1.0p64); result.exponent -= 64; } else { // frexp(+-0) = (+-0, 0) result.significand = x; result.exponent = 0; } return result; } else if (e == 0x7FF) { // frexp(nan) = (nan, undefined) result.significand = x; result.exponent = undefined; // frexp(+-inf) = (+-inf, 0) if (math.isInf(x)) { result.exponent = 0; } return result; } result.exponent = e - 0x3FE; y &= 0x800FFFFFFFFFFFFF; y |= 0x3FE0000000000000; result.significand = @as(f64, @bitCast(y)); return result; } fn frexp128(x: f128) Frexp(f128) { var result: Frexp(f128) = undefined; var y = @as(u128, @bitCast(x)); const e = @as(i32, @intCast(y >> 112)) & 0x7FFF; if (e == 0) { if (x != 0) { // subnormal result = frexp128(x * 0x1.0p120); result.exponent -= 120; } else { // frexp(+-0) = (+-0, 0) result.significand = x; result.exponent = 0; } return result; } else if (e == 0x7FFF) { // frexp(nan) = (nan, undefined) result.significand = x; result.exponent = undefined; // frexp(+-inf) = (+-inf, 0) if (math.isInf(x)) { result.exponent = 0; } return result; } result.exponent = e - 0x3FFE; y &= 0x8000FFFFFFFFFFFFFFFFFFFFFFFFFFFF; y |= 0x3FFE0000000000000000000000000000; result.significand = @as(f128, @bitCast(y)); return result; } |
Test:type dispatch |
test "type dispatch" { const a = frexp(@as(f32, 1.3)); const b = frexp32(1.3); try expect(a.significand == b.significand and a.exponent == b.exponent); const c = frexp(@as(f64, 1.3)); const d = frexp64(1.3); try expect(c.significand == d.significand and c.exponent == d.exponent); const e = frexp(@as(f128, 1.3)); const f = frexp128(1.3); try expect(e.significand == f.significand and e.exponent == f.exponent); } |
Test:32 |
test "32" { const epsilon = 0.000001; var r: Frexp(f32) = undefined; r = frexp32(1.3); try expect(math.approxEqAbs(f32, r.significand, 0.65, epsilon) and r.exponent == 1); r = frexp32(78.0234); try expect(math.approxEqAbs(f32, r.significand, 0.609558, epsilon) and r.exponent == 7); } |
Test:64 |
test "64" { const epsilon = 0.000001; var r: Frexp(f64) = undefined; r = frexp64(1.3); try expect(math.approxEqAbs(f64, r.significand, 0.65, epsilon) and r.exponent == 1); r = frexp64(78.0234); try expect(math.approxEqAbs(f64, r.significand, 0.609558, epsilon) and r.exponent == 7); } |
Test:128 |
test "128" { const epsilon = 0.000001; var r: Frexp(f128) = undefined; r = frexp128(1.3); try expect(math.approxEqAbs(f128, r.significand, 0.65, epsilon) and r.exponent == 1); r = frexp128(78.0234); try expect(math.approxEqAbs(f128, r.significand, 0.609558, epsilon) and r.exponent == 7); } |
Test:32 special |
test "32 special" { var r: Frexp(f32) = undefined; r = frexp32(0.0); try expect(r.significand == 0.0 and r.exponent == 0); r = frexp32(-0.0); try expect(r.significand == -0.0 and r.exponent == 0); r = frexp32(math.inf(f32)); try expect(math.isPositiveInf(r.significand) and r.exponent == 0); r = frexp32(-math.inf(f32)); try expect(math.isNegativeInf(r.significand) and r.exponent == 0); r = frexp32(math.nan(f32)); try expect(math.isNan(r.significand)); } |
Test:64 special |
test "64 special" { var r: Frexp(f64) = undefined; r = frexp64(0.0); try expect(r.significand == 0.0 and r.exponent == 0); r = frexp64(-0.0); try expect(r.significand == -0.0 and r.exponent == 0); r = frexp64(math.inf(f64)); try expect(math.isPositiveInf(r.significand) and r.exponent == 0); r = frexp64(-math.inf(f64)); try expect(math.isNegativeInf(r.significand) and r.exponent == 0); r = frexp64(math.nan(f64)); try expect(math.isNan(r.significand)); } |
Test:128 special |
test "128 special" { var r: Frexp(f128) = undefined; r = frexp128(0.0); try expect(r.significand == 0.0 and r.exponent == 0); r = frexp128(-0.0); try expect(r.significand == -0.0 and r.exponent == 0); r = frexp128(math.inf(f128)); try expect(math.isPositiveInf(r.significand) and r.exponent == 0); r = frexp128(-math.inf(f128)); try expect(math.isNegativeInf(r.significand) and r.exponent == 0); r = frexp128(math.nan(f128)); try expect(math.isNan(r.significand)); } |
Generated by zstd-browse2 on 2023-11-04 14:12:21 -0400. |