From a2f5f0da5c21dd89834ec2b284ef2e7d2f5851a2 Mon Sep 17 00:00:00 2001 From: viri Date: Thu, 7 Apr 2022 01:24:46 -0600 Subject: [PATCH] std.math.isFinite: make generic, support f80 --- lib/std/math/isfinite.zig | 74 +++++++++++++++------------------------ 1 file changed, 29 insertions(+), 45 deletions(-) diff --git a/lib/std/math/isfinite.zig b/lib/std/math/isfinite.zig index 762fb39991..77aab8bf76 100644 --- a/lib/std/math/isfinite.zig +++ b/lib/std/math/isfinite.zig @@ -1,59 +1,43 @@ const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; -const maxInt = std.math.maxInt; /// Returns whether x is a finite value. pub fn isFinite(x: anytype) bool { const T = @TypeOf(x); - switch (T) { - f16 => { - const bits = @bitCast(u16, x); - return bits & 0x7FFF < 0x7C00; - }, - f32 => { - const bits = @bitCast(u32, x); - return bits & 0x7FFFFFFF < 0x7F800000; - }, - f64 => { - const bits = @bitCast(u64, x); - return bits & (maxInt(u64) >> 1) < (0x7FF << 52); - }, - f128 => { - const bits = @bitCast(u128, x); - return bits & (maxInt(u128) >> 1) < (0x7FFF << 112); - }, - else => { - @compileError("isFinite not implemented for " ++ @typeName(T)); - }, + const TBits = std.meta.Int(.unsigned, @bitSizeOf(T)); + if (@typeInfo(T) != .Float) { + @compileError("isFinite not implemented for " ++ @typeName(T)); } + const exponent_bits = math.floatExponentBits(T); + const mantissa_bits = math.floatMantissaBits(T); + const all1s_exponent = ((1 << exponent_bits) - 1) << mantissa_bits; + const remove_sign = ~@as(TBits, 0) >> 1; + return @bitCast(TBits, x) & remove_sign < all1s_exponent; } test "math.isFinite" { - try expect(isFinite(@as(f16, 0.0))); - try expect(isFinite(@as(f16, -0.0))); - try expect(isFinite(@as(f32, 0.0))); - try expect(isFinite(@as(f32, -0.0))); - try expect(isFinite(@as(f64, 0.0))); - try expect(isFinite(@as(f64, -0.0))); - try expect(isFinite(@as(f128, 0.0))); - try expect(isFinite(@as(f128, -0.0))); + // TODO remove when #11391 is resolved + if (@import("builtin").os.tag == .freebsd) return error.SkipZigTest; - try expect(!isFinite(math.inf(f16))); - try expect(!isFinite(-math.inf(f16))); - try expect(!isFinite(math.inf(f32))); - try expect(!isFinite(-math.inf(f32))); - try expect(!isFinite(math.inf(f64))); - try expect(!isFinite(-math.inf(f64))); - try expect(!isFinite(math.inf(f128))); - try expect(!isFinite(-math.inf(f128))); + inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| { + // normals + try expect(isFinite(@as(T, 1.0))); + try expect(isFinite(-@as(T, 1.0))); - try expect(!isFinite(math.nan(f16))); - try expect(!isFinite(-math.nan(f16))); - try expect(!isFinite(math.nan(f32))); - try expect(!isFinite(-math.nan(f32))); - try expect(!isFinite(math.nan(f64))); - try expect(!isFinite(-math.nan(f64))); - try expect(!isFinite(math.nan(f128))); - try expect(!isFinite(-math.nan(f128))); + // zero & subnormals + try expect(isFinite(@as(T, 0.0))); + try expect(isFinite(@as(T, -0.0))); + try expect(isFinite(math.floatTrueMin(T))); + + // other float limits + try expect(isFinite(math.floatMin(T))); + try expect(isFinite(math.floatMax(T))); + + // inf & nan + try expect(!isFinite(math.inf(T))); + try expect(!isFinite(-math.inf(T))); + try expect(!isFinite(math.nan(T))); + try expect(!isFinite(-math.nan(T))); + } }