| ... | @@ -611,15 +611,15 @@ pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) t | ... | @@ -611,15 +611,15 @@ pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) t |
| 611 | if (from == 0 and to == 0) { | 611 | if (from == 0 and to == 0) { |
| 612 | return u0; | 612 | return u0; |
| 613 | } | 613 | } |
| 614 | const sign: std.builtin.Signedness = if (from < 0) .signed else .unsigned; | 614 | const signedness: std.builtin.Signedness = if (from < 0) .signed else .unsigned; |
| 615 | const largest_positive_integer = max(if (from < 0) (-from) - 1 else from, to); // two's complement | 615 | const largest_positive_integer = max(if (from < 0) (-from) - 1 else from, to); // two's complement |
| 616 | const base = log2(largest_positive_integer); | 616 | const base = log2(largest_positive_integer); |
| 617 | const upper = (1 << base) - 1; | 617 | const upper = (1 << base) - 1; |
| 618 | var magnitude_bits = if (upper >= largest_positive_integer) base else base + 1; | 618 | var magnitude_bits = if (upper >= largest_positive_integer) base else base + 1; |
| 619 | if (sign == .signed) { | 619 | if (signedness == .signed) { |
| 620 | magnitude_bits += 1; | 620 | magnitude_bits += 1; |
| 621 | } | 621 | } |
| 622 | return std.meta.Int(sign, magnitude_bits); | 622 | return std.meta.Int(signedness, magnitude_bits); |
| 623 | } | 623 | } |
| 624 | | 624 | |
| 625 | test "IntFittingRange" { | 625 | test "IntFittingRange" { |
| ... | @@ -1447,3 +1447,112 @@ pub fn break_f80(x: f80) F80 { | ... | @@ -1447,3 +1447,112 @@ pub fn break_f80(x: f80) F80 { |
| 1447 | .exp = @truncate(u16, int >> 64), | 1447 | .exp = @truncate(u16, int >> 64), |
| 1448 | }; | 1448 | }; |
| 1449 | } | 1449 | } |
| | 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. |
| | 1456 | pub 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 | |
| | 1476 | fn 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 | |
| | 1555 | test "sign" { |
| | 1556 | try testSign(); |
| | 1557 | comptime try testSign(); |
| | 1558 | } |