-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Add @depositBits and @extractBits builtins
#15285
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
72c77d5
9862b07
ad8bff8
befa47f
70d2dc4
98f70c0
472734e
a4ae063
fb1cb9f
d4da312
3015a6a
c13a54f
b2bba7a
3792b6e
1843795
af42a76
1e8c707
3d6e308
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2762,6 +2762,54 @@ fn popCountTest(val: *const Managed, bit_count: usize, expected: usize) !void { | |
| try testing.expectEqual(expected, val.toConst().popCount(bit_count)); | ||
| } | ||
|
|
||
| test "big int extractBits" { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some possible tests to have more confidence everything is correct:
Random input can be taken like this: const RndGen = std.rand.DefaultPrng;
var rnd = RndGen.init(42);
var i: u32 = 0;
while (i < 10_000) : (i += 1) {
var rand_num = rnd.random().int(i64);
try test__popcountdi2(rand_num);
}
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah issue with creating the destination value is that we need to have a known-good implementation to generate it. I guess we could just write this in regular Zig though and converting to a bigint.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm actually a bit skeptical of this now, since the actual opportunities for mistakes here would be around having multiple limbs. Generating random
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I would expect the main problems to be in either the bit mask logic or the limbs not getting properly initialized. My suggestion was more of an brute-force approach, but listing the edge cases should also work.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm. I think we should look at a more reasoned set of tests then. The current ones effectively just test the basic bitmask logic, it'd be good to add some more to ensure that the boundaries between limbs are handled correctly, and that a difference in sizes is handled correctly. I'm fairly confident in both of these, but definitely can't hurt to strengthen this.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Uninitialised limbs aren't a worry though, since the output bigint is set to zero at the beginning. |
||
| try extractBitsTest(0x12345678, 0x0, 0x0); | ||
| try extractBitsTest(0x12345678, 0xf0f0f0f0, 0x1357); | ||
| try extractBitsTest(0x12345678, 0xff00ff00, 0x1256); | ||
| try extractBitsTest(0x12345678, 0xffff, 0x5678); | ||
|
|
||
| try extractBitsTest(0x12345678_90123456_78901234_56789012, 0xff << 64, 0x56); | ||
| try extractBitsTest(0x12345678_90123456_78901234_56789012, (0xff << 64) | 0xff00f, 0x56892); | ||
| } | ||
|
|
||
| fn extractBitsTest(comptime source: comptime_int, comptime mask: comptime_int, comptime expected: comptime_int) !void { | ||
| var source_bigint = try Managed.initSet(testing.allocator, source); | ||
| defer source_bigint.deinit(); | ||
| var mask_bigint = try Managed.initSet(testing.allocator, mask); | ||
| defer mask_bigint.deinit(); | ||
| const limbs = try testing.allocator.alloc(Limb, mask_bigint.limbs.len); | ||
| defer testing.allocator.free(limbs); | ||
| var result = Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; | ||
|
|
||
| result.extractBits(source_bigint.toConst(), mask_bigint.toConst()); | ||
|
|
||
| try testing.expectEqual(std.math.Order.eq, result.toConst().orderAgainstScalar(expected)); | ||
| } | ||
|
|
||
| test "big int depositBits" { | ||
| try depositBitsTest(0x12345678, 0x0, 0x0); | ||
| try depositBitsTest(0x12345678, 0xf0f0f0f0, 0x50607080); | ||
| try depositBitsTest(0x12345678, 0xff00ff00, 0x56007800); | ||
| try depositBitsTest(0x12345678, 0xffff, 0x5678); | ||
|
|
||
| try depositBitsTest(0x1234, 0xff << 64, 0x34_00000000_00000000); | ||
| try depositBitsTest(0x12345678, (0xff << 64) | 0xff00f, 0x45_00000000_00067008); | ||
| } | ||
|
|
||
| fn depositBitsTest(comptime source: comptime_int, comptime mask: comptime_int, comptime expected: comptime_int) !void { | ||
| var source_bigint = try Managed.initSet(testing.allocator, source); | ||
| defer source_bigint.deinit(); | ||
| var mask_bigint = try Managed.initSet(testing.allocator, mask); | ||
| defer mask_bigint.deinit(); | ||
| const limbs = try testing.allocator.alloc(Limb, mask_bigint.limbs.len); | ||
| defer testing.allocator.free(limbs); | ||
| var result = Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; | ||
|
|
||
| result.depositBits(source_bigint.toConst(), mask_bigint.toConst()); | ||
|
|
||
| try testing.expectEqual(std.math.Order.eq, result.toConst().orderAgainstScalar(expected)); | ||
| } | ||
|
|
||
| test "big int conversion read/write twos complement" { | ||
| var a = try Managed.initSet(testing.allocator, (1 << 493) - 1); | ||
| defer a.deinit(); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.