Skip to content

Commit 7c5352f

Browse files
committed
std.math.sign: Narrow integer return types to possible values
This may be a breaking change for callers that depend on the return type being identical to the input type. For example, `sign(u32) * i8 + i8` could now overflow. Callers can add an explicit type annotation to avoid that situation. If Zig ever allows small integer types to coerce to floats (see #18614), then it might make sense to always return an integer. In the meantime, I figured it would be too annoying for users dealing with floats.
1 parent 3be6809 commit 7c5352f

File tree

1 file changed

+16
-4
lines changed

1 file changed

+16
-4
lines changed

lib/std/math.zig

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1735,12 +1735,24 @@ pub const F80 = struct {
17351735
}
17361736
};
17371737

1738+
fn Sign(T: type) type {
1739+
return switch (@typeInfo(T)) {
1740+
.int => |int| IntFittingRange(if (int.signedness == .signed) -1 else 0, 1),
1741+
.vector => |vec| switch (@typeInfo(vec.child)) {
1742+
.int => |int| @Vector(vec.len, IntFittingRange(if (int.signedness == .signed) -1 else 0, 1)),
1743+
else => T,
1744+
},
1745+
else => T,
1746+
};
1747+
}
1748+
17381749
/// Returns -1, 0, or 1.
17391750
/// Supports integer and float types and vectors of integer and float types.
17401751
/// Unsigned integer types will always return 0 or 1.
1752+
/// Returned integer types are narrowed to fit the possible values.
17411753
/// Branchless.
1742-
pub inline fn sign(i: anytype) @TypeOf(i) {
1743-
const T = @TypeOf(i);
1754+
pub inline fn sign(i: anytype) Sign(@TypeOf(i)) {
1755+
const T = Sign(@TypeOf(i));
17441756
return switch (@typeInfo(T)) {
17451757
.int, .comptime_int => @as(T, @intFromBool(i > 0)) - @as(T, @intFromBool(i < 0)),
17461758
.float, .comptime_float => @as(T, @floatFromInt(@intFromBool(i > 0))) - @as(T, @floatFromInt(@intFromBool(i < 0))),
@@ -1751,10 +1763,10 @@ pub inline fn sign(i: anytype) @TypeOf(i) {
17511763
const one: T = @splat(1);
17521764
break :blk @select(vinfo.child, i > zero, one, zero) - @select(vinfo.child, i < zero, one, zero);
17531765
},
1754-
else => @compileError("Expected vector of ints or floats, found " ++ @typeName(T)),
1766+
else => @compileError("Expected a vector of ints or floats, found " ++ @typeName(@TypeOf(i))),
17551767
}
17561768
},
1757-
else => @compileError("Expected an int, float or vector of one, found " ++ @typeName(T)),
1769+
else => @compileError("Expected an int, float, or a vector of one, found " ++ @typeName(@TypeOf(i))),
17581770
};
17591771
}
17601772

0 commit comments

Comments
 (0)