authorgravatar for twostepted@gmail.comTravis Staloch <twostepted@gmail.com> 2022-05-11 16:33:55-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-12 16:09:09-04:00
log974af5f29101ce8d000359b749f35a2b07c90a32
tree1b183a11fac5d1ae25532964655e1fea96c83615
parent5c20c7036bebe443a22a4961ee8f2cd37f65a643

add std.math.sign


1 files changed, 112 insertions(+), 3 deletions(-)

lib/std/math.zig+112-3
......@@ -611,15 +611,15 @@ pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) t
611611 if (from == 0 and to == 0) {
612612 return u0;
613613 }
614 const sign: std.builtin.Signedness = if (from < 0) .signed else .unsigned;
614 const signedness: std.builtin.Signedness = if (from < 0) .signed else .unsigned;
615615 const largest_positive_integer = max(if (from < 0) (-from) - 1 else from, to); // two's complement
616616 const base = log2(largest_positive_integer);
617617 const upper = (1 << base) - 1;
618618 var magnitude_bits = if (upper >= largest_positive_integer) base else base + 1;
619 if (sign == .signed) {
619 if (signedness == .signed) {
620620 magnitude_bits += 1;
621621 }
622 return std.meta.Int(sign, magnitude_bits);
622 return std.meta.Int(signedness, magnitude_bits);
623623}
624624
625625test "IntFittingRange" {
......@@ -1447,3 +1447,112 @@ pub fn break_f80(x: f80) F80 {
14471447 .exp = @truncate(u16, int >> 64),
14481448 };
14491449}
1450
1451/// Returns -1, 0, or 1.
1452/// Supports integer types, vectors of integer types, and float types.
1453/// Unsigned integer types will always return 0 or 1.
1454/// TODO: support vectors of floats
1455/// Branchless.
1456pub inline fn sign(i: anytype) @TypeOf(i) {
1457 const T = @TypeOf(i);
1458 return switch (@typeInfo(T)) {
1459 .Int, .ComptimeInt => @as(T, @boolToInt(i > 0)) - @boolToInt(i < 0),
1460 .Float, .ComptimeFloat => @intToFloat(T, @boolToInt(i > 0)) - @intToFloat(T, @boolToInt(i < 0)),
1461 .Vector => |vinfo| blk: {
1462 const u1xN = std.meta.Vector(vinfo.len, u1);
1463 break :blk switch (@typeInfo(vinfo.child)) {
1464 .Int => @as(T, @bitCast(u1xN, i > @splat(vinfo.len, @as(vinfo.child, 0)))) -
1465 @as(T, @bitCast(u1xN, i < @splat(vinfo.len, @as(vinfo.child, 0)))),
1466 .Float => @compileError("TODO: add support for vectors of floats once @intToFloat accepts vector types"),
1467 // break :blk @intToFloat(T, @bitCast(u1xN, i > @splat(vinfo.len, @as(vinfo.child, 0)))) -
1468 // @intToFloat(T, @bitCast(u1xN, i < @splat(vinfo.len, @as(vinfo.child, 0)))),
1469 else => @compileError("Expected vector of ints or floats, found " ++ @typeName(T)),
1470 };
1471 },
1472 else => @compileError("Expected an int, float or vector of one, found " ++ @typeName(T)),
1473 };
1474}
1475
1476fn testSign() !void {
1477 // each of the following blocks checks the inputs
1478 // 2, -2, 0, { 2, -2, 0 } provide expected output
1479 // 1, -1, 0, { 1, -1, 0 } for the given T
1480 // (negative values omitted for unsigned types)
1481 {
1482 const T = i8;
1483 try std.testing.expectEqual(@as(T, 1), sign(@as(T, 2)));
1484 try std.testing.expectEqual(@as(T, -1), sign(@as(T, -2)));
1485 try std.testing.expectEqual(@as(T, 0), sign(@as(T, 0)));
1486 try std.testing.expectEqual(@Vector(3, T){ 1, -1, 0 }, sign(@Vector(3, T){ 2, -2, 0 }));
1487 }
1488 {
1489 const T = i32;
1490 try std.testing.expectEqual(@as(T, 1), sign(@as(T, 2)));
1491 try std.testing.expectEqual(@as(T, -1), sign(@as(T, -2)));
1492 try std.testing.expectEqual(@as(T, 0), sign(@as(T, 0)));
1493 try std.testing.expectEqual(@Vector(3, T){ 1, -1, 0 }, sign(@Vector(3, T){ 2, -2, 0 }));
1494 }
1495 {
1496 const T = i64;
1497 try std.testing.expectEqual(@as(T, 1), sign(@as(T, 2)));
1498 try std.testing.expectEqual(@as(T, -1), sign(@as(T, -2)));
1499 try std.testing.expectEqual(@as(T, 0), sign(@as(T, 0)));
1500 try std.testing.expectEqual(@Vector(3, T){ 1, -1, 0 }, sign(@Vector(3, T){ 2, -2, 0 }));
1501 }
1502 {
1503 const T = u8;
1504 try std.testing.expectEqual(@as(T, 1), sign(@as(T, 2)));
1505 try std.testing.expectEqual(@as(T, 0), sign(@as(T, 0)));
1506 try std.testing.expectEqual(@Vector(2, T){ 1, 0 }, sign(@Vector(2, T){ 2, 0 }));
1507 }
1508 {
1509 const T = u32;
1510 try std.testing.expectEqual(@as(T, 1), sign(@as(T, 2)));
1511 try std.testing.expectEqual(@as(T, 0), sign(@as(T, 0)));
1512 try std.testing.expectEqual(@Vector(2, T){ 1, 0 }, sign(@Vector(2, T){ 2, 0 }));
1513 }
1514 {
1515 const T = u64;
1516 try std.testing.expectEqual(@as(T, 1), sign(@as(T, 2)));
1517 try std.testing.expectEqual(@as(T, 0), sign(@as(T, 0)));
1518 try std.testing.expectEqual(@Vector(2, T){ 1, 0 }, sign(@Vector(2, T){ 2, 0 }));
1519 }
1520 {
1521 const T = f16;
1522 try std.testing.expectEqual(@as(T, 1), sign(@as(T, 2)));
1523 try std.testing.expectEqual(@as(T, -1), sign(@as(T, -2)));
1524 try std.testing.expectEqual(@as(T, 0), sign(@as(T, 0)));
1525 // TODO - uncomment once @intToFloat supports vectors
1526 // try std.testing.expectEqual(@Vector(3, T){ 1, -1, 0 }, sign(@Vector(3, T){ 2, -2, 0 }));
1527 }
1528 {
1529 const T = f32;
1530 try std.testing.expectEqual(@as(T, 1), sign(@as(T, 2)));
1531 try std.testing.expectEqual(@as(T, -1), sign(@as(T, -2)));
1532 try std.testing.expectEqual(@as(T, 0), sign(@as(T, 0)));
1533 // TODO - uncomment once @intToFloat supports vectors
1534 // try std.testing.expectEqual(@Vector(3, T){ 1, -1, 0 }, sign(@Vector(3, T){ 2, -2, 0 }));
1535 }
1536 {
1537 const T = f64;
1538 try std.testing.expectEqual(@as(T, 1), sign(@as(T, 2)));
1539 try std.testing.expectEqual(@as(T, -1), sign(@as(T, -2)));
1540 try std.testing.expectEqual(@as(T, 0), sign(@as(T, 0)));
1541 // TODO - uncomment once @intToFloat supports vectors
1542 // try std.testing.expectEqual(@Vector(3, T){ 1, -1, 0 }, sign(@Vector(3, T){ 2, -2, 0 }));
1543 }
1544
1545 // comptime_int
1546 try std.testing.expectEqual(-1, sign(-10));
1547 try std.testing.expectEqual(1, sign(10));
1548 try std.testing.expectEqual(0, sign(0));
1549 // comptime_float
1550 try std.testing.expectEqual(-1.0, sign(-10.0));
1551 try std.testing.expectEqual(1.0, sign(10.0));
1552 try std.testing.expectEqual(0.0, sign(0.0));
1553}
1554
1555test "sign" {
1556 try testSign();
1557 comptime try testSign();
1558}