authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2019-06-02 22:09:22-07:00
committergravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2019-06-02 22:09:22-07:00
log9bed6e1bf94b79ff027cb5aab3fa7231973337a9
tree6b6cbe3a81dc2f5fb018940cda50b04665b04acc
parent3eca5a42e650878922437a854a352300052c878a

std.math: Add ceilPowerOfTwo and ceilPowerOfTwoPromote

Closes #2426

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

std/math.zig+72-9
...@@ -696,6 +696,78 @@ test "math.floorPowerOfTwo" {...@@ -696,6 +696,78 @@ test "math.floorPowerOfTwo" {
696 comptime testFloorPowerOfTwo();696 comptime testFloorPowerOfTwo();
697}697}
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/// Result is a type with 1 more bit than the input type.
710pub fn ceilPowerOfTwoPromote(comptime T: type, value: T) @IntType(T.is_signed, T.bit_count + 1) {
711 if (T.is_signed) {
712 @compileError("signed integers not supported");
713 }
714 comptime const promotedType = @IntType(T.is_signed, T.bit_count + 1);
715 comptime const shiftType = std.math.Log2Int(promotedType);
716 if (value == 0) return promotedType(0);
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/// If the value doesn't fit, returns an error.
722pub fn ceilPowerOfTwo(comptime T: type, value: T) (error{Overflow}!T) {
723 if (T.is_signed) {
724 @compileError("signed integers not supported");
725 }
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(0), ceilPowerOfTwoPromote(u32, 0));
742 testing.expectEqual(u33(1), ceilPowerOfTwoPromote(u32, 1));
743 testing.expectEqual(u33(2), ceilPowerOfTwoPromote(u32, 2));
744 testing.expectEqual(u33(64), ceilPowerOfTwoPromote(u32, 63));
745 testing.expectEqual(u33(64), ceilPowerOfTwoPromote(u32, 64));
746 testing.expectEqual(u33(128), ceilPowerOfTwoPromote(u32, 65));
747 testing.expectEqual(u6(8), ceilPowerOfTwoPromote(u5, 7));
748 testing.expectEqual(u6(8), ceilPowerOfTwoPromote(u5, 8));
749 testing.expectEqual(u6(16), ceilPowerOfTwoPromote(u5, 9));
750 testing.expectEqual(u5(16), ceilPowerOfTwoPromote(u4, 9));
751}
752
753test "math.ceilPowerOfTwo" {
754 try testCeilPowerOfTwo();
755 comptime try testCeilPowerOfTwo();
756}
757
758fn testCeilPowerOfTwo() !void {
759 testing.expectEqual(u32(0), try ceilPowerOfTwo(u32, 0));
760 testing.expectEqual(u32(1), try ceilPowerOfTwo(u32, 1));
761 testing.expectEqual(u32(2), try ceilPowerOfTwo(u32, 2));
762 testing.expectEqual(u32(64), try ceilPowerOfTwo(u32, 63));
763 testing.expectEqual(u32(64), try ceilPowerOfTwo(u32, 64));
764 testing.expectEqual(u32(128), try ceilPowerOfTwo(u32, 65));
765 testing.expectEqual(u5(8), try ceilPowerOfTwo(u5, 7));
766 testing.expectEqual(u5(8), try ceilPowerOfTwo(u5, 8));
767 testing.expectEqual(u5(16), try ceilPowerOfTwo(u5, 9));
768 testing.expectError(error.Overflow, ceilPowerOfTwo(u4, 9));
769}
770
699pub fn log2_int(comptime T: type, x: T) Log2Int(T) {771pub fn log2_int(comptime T: type, x: T) Log2Int(T) {
700 assert(x != 0);772 assert(x != 0);
701 return @intCast(Log2Int(T), T.bit_count - 1 - @clz(T, x));773 return @intCast(Log2Int(T), T.bit_count - 1 - @clz(T, x));
...@@ -722,15 +794,6 @@ test "std.math.log2_int_ceil" {...@@ -722,15 +794,6 @@ test "std.math.log2_int_ceil" {
722 testing.expect(log2_int_ceil(u32, 10) == 4);794 testing.expect(log2_int_ceil(u32, 10) == 4);
723}795}
724796
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
734pub fn lossyCast(comptime T: type, value: var) T {797pub fn lossyCast(comptime T: type, value: var) T {
735 switch (@typeInfo(@typeOf(value))) {798 switch (@typeInfo(@typeOf(value))) {
736 builtin.TypeId.Int => return @intToFloat(T, value),799 builtin.TypeId.Int => return @intToFloat(T, value),