authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-06-04 23:24:34-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2019-06-04 23:24:34-04:00
logca989a95d3ccf65a8bdd69d5f95e196927f91d8f
tree9982c922b6e4419ab3cbdfebf8cd1a4595d81ef5
parentd83b15febf00518e201160f8b089c0d846d18e4c
parenta0d66fa1e6e8b9620e4990a33c32b0db11469aec
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #2617 from squeek502/ceil-power-of-two

std.math: Add ceilPowerOfTwo and ceilPowerOfTwoPromote

1 files changed, 70 insertions(+), 9 deletions(-)

std/math.zig+70-9
......@@ -696,6 +696,76 @@ test "math.floorPowerOfTwo" {
696696 comptime testFloorPowerOfTwo();
697697}
698698
699fn testFloorPowerOfTwo() void {
700 testing.expect(floorPowerOfTwo(u32, 63) == 32);
701 testing.expect(floorPowerOfTwo(u32, 64) == 64);
702 testing.expect(floorPowerOfTwo(u32, 65) == 64);
703 testing.expect(floorPowerOfTwo(u4, 7) == 4);
704 testing.expect(floorPowerOfTwo(u4, 8) == 8);
705 testing.expect(floorPowerOfTwo(u4, 9) == 8);
706}
707
708/// Returns the next power of two (if the value is not already a power of two).
709/// Only unsigned integers can be used. Zero is not an allowed input.
710/// Result is a type with 1 more bit than the input type.
711pub fn ceilPowerOfTwoPromote(comptime T: type, value: T) @IntType(T.is_signed, T.bit_count + 1) {
712 comptime assert(@typeId(T) == builtin.TypeId.Int);
713 comptime assert(!T.is_signed);
714 assert(value != 0);
715 comptime const promotedType = @IntType(T.is_signed, T.bit_count + 1);
716 comptime const shiftType = std.math.Log2Int(promotedType);
717 return promotedType(1) << @intCast(shiftType, T.bit_count - @clz(T, value - 1));
718}
719
720/// Returns the next power of two (if the value is not already a power of two).
721/// Only unsigned integers can be used. Zero is not an allowed input.
722/// If the value doesn't fit, returns an error.
723pub fn ceilPowerOfTwo(comptime T: type, value: T) (error{Overflow}!T) {
724 comptime assert(@typeId(T) == builtin.TypeId.Int);
725 comptime assert(!T.is_signed);
726 comptime const promotedType = @IntType(T.is_signed, T.bit_count + 1);
727 comptime const overflowBit = promotedType(1) << T.bit_count;
728 var x = ceilPowerOfTwoPromote(T, value);
729 if (overflowBit & x != 0) {
730 return error.Overflow;
731 }
732 return @intCast(T, x);
733}
734
735test "math.ceilPowerOfTwoPromote" {
736 testCeilPowerOfTwoPromote();
737 comptime testCeilPowerOfTwoPromote();
738}
739
740fn testCeilPowerOfTwoPromote() void {
741 testing.expectEqual(u33(1), ceilPowerOfTwoPromote(u32, 1));
742 testing.expectEqual(u33(2), ceilPowerOfTwoPromote(u32, 2));
743 testing.expectEqual(u33(64), ceilPowerOfTwoPromote(u32, 63));
744 testing.expectEqual(u33(64), ceilPowerOfTwoPromote(u32, 64));
745 testing.expectEqual(u33(128), ceilPowerOfTwoPromote(u32, 65));
746 testing.expectEqual(u6(8), ceilPowerOfTwoPromote(u5, 7));
747 testing.expectEqual(u6(8), ceilPowerOfTwoPromote(u5, 8));
748 testing.expectEqual(u6(16), ceilPowerOfTwoPromote(u5, 9));
749 testing.expectEqual(u5(16), ceilPowerOfTwoPromote(u4, 9));
750}
751
752test "math.ceilPowerOfTwo" {
753 try testCeilPowerOfTwo();
754 comptime try testCeilPowerOfTwo();
755}
756
757fn testCeilPowerOfTwo() !void {
758 testing.expectEqual(u32(1), try ceilPowerOfTwo(u32, 1));
759 testing.expectEqual(u32(2), try ceilPowerOfTwo(u32, 2));
760 testing.expectEqual(u32(64), try ceilPowerOfTwo(u32, 63));
761 testing.expectEqual(u32(64), try ceilPowerOfTwo(u32, 64));
762 testing.expectEqual(u32(128), try ceilPowerOfTwo(u32, 65));
763 testing.expectEqual(u5(8), try ceilPowerOfTwo(u5, 7));
764 testing.expectEqual(u5(8), try ceilPowerOfTwo(u5, 8));
765 testing.expectEqual(u5(16), try ceilPowerOfTwo(u5, 9));
766 testing.expectError(error.Overflow, ceilPowerOfTwo(u4, 9));
767}
768
699769pub fn log2_int(comptime T: type, x: T) Log2Int(T) {
700770 assert(x != 0);
701771 return @intCast(Log2Int(T), T.bit_count - 1 - @clz(T, x));
......@@ -722,15 +792,6 @@ test "std.math.log2_int_ceil" {
722792 testing.expect(log2_int_ceil(u32, 10) == 4);
723793}
724794
725fn testFloorPowerOfTwo() void {
726 testing.expect(floorPowerOfTwo(u32, 63) == 32);
727 testing.expect(floorPowerOfTwo(u32, 64) == 64);
728 testing.expect(floorPowerOfTwo(u32, 65) == 64);
729 testing.expect(floorPowerOfTwo(u4, 7) == 4);
730 testing.expect(floorPowerOfTwo(u4, 8) == 8);
731 testing.expect(floorPowerOfTwo(u4, 9) == 8);
732}
733
734795pub fn lossyCast(comptime T: type, value: var) T {
735796 switch (@typeInfo(@typeOf(value))) {
736797 builtin.TypeId.Int => return @intToFloat(T, value),