| ... | ... | @@ -611,15 +611,15 @@ pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) t |
| 611 | 611 | if (from == 0 and to == 0) { |
| 612 | 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 | 615 | const largest_positive_integer = max(if (from < 0) (-from) - 1 else from, to); // two's complement |
| 616 | 616 | const base = log2(largest_positive_integer); |
| 617 | 617 | const upper = (1 << base) - 1; |
| 618 | 618 | var magnitude_bits = if (upper >= largest_positive_integer) base else base + 1; |
| 619 | | if (sign == .signed) { |
| 619 | if (signedness == .signed) { |
| 620 | 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 | 625 | test "IntFittingRange" { |
| ... | ... | @@ -1447,3 +1447,112 @@ pub fn break_f80(x: f80) F80 { |
| 1447 | 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 | } |