authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-15 01:05:50+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-15 01:05:50+01:00
log80b5917fad7fb9d743ef78c0b4ac260511acaf6d
treebee845c5cc5266f9141e00be02faef05714ef26a
parent648c1c5d28f3c3b1da1acf326b733c47436007d1
parent688af047255790d9aec4a1152eaa525f7dd5b46d

Merge pull request 'Bigint improvements' (#30100) from unplanned/zig:bigint-improvements into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/30100 Reviewed-by: jedisct1 <jedisct1@noreply.codeberg.org>

2 files changed, 84 insertions(+), 43 deletions(-)

lib/std/math/big/int.zig+60-19
...@@ -17,6 +17,27 @@ const Endian = std.builtin.Endian;...@@ -17,6 +17,27 @@ const Endian = std.builtin.Endian;
17const Signedness = std.builtin.Signedness;17const Signedness = std.builtin.Signedness;
18const native_endian = builtin.cpu.arch.endian();18const native_endian = builtin.cpu.arch.endian();
1919
20// Comptime-computed constants for supported bases (2 - 36)
21// all values are set to 0 for bases 0 - 1, to make it possible to
22// access a constant for a given base b using `constants.value[b]`
23const Constants = struct {
24 // big_bases[b] is the biggest power of b that fit in a single Limb
25 // i.e. big_bases[b] = b^k < 2^@bitSizeOf(Limb) and b^(k+1) >= 2^@bitSizeOf(Limb)
26 big_bases: [37]Limb,
27 // digits_per_limb[b] is the value of k used in the previous field
28 digits_per_limb: [37]u8,
29};
30const constants: Constants = blk: {
31 @setEvalBranchQuota(2000);
32 var digits_per_limb = [_]u8{0} ** 37;
33 var bases = [_]Limb{0} ** 37;
34 for (2..37) |base| {
35 digits_per_limb[base] = @intCast(math.log(Limb, base, math.maxInt(Limb)));
36 bases[base] = std.math.pow(Limb, base, digits_per_limb[base]);
37 }
38 break :blk Constants{ .big_bases = bases, .digits_per_limb = digits_per_limb };
39};
40
20/// Returns the number of limbs needed to store `scalar`, which must be a41/// Returns the number of limbs needed to store `scalar`, which must be a
21/// primitive integer or float value.42/// primitive integer or float value.
22/// Note: A comptime-known upper bound of this value that may be used43/// Note: A comptime-known upper bound of this value that may be used
...@@ -329,23 +350,15 @@ pub const Mutable = struct {...@@ -329,23 +350,15 @@ pub const Mutable = struct {
329 /// not allowed (e.g. 0x43 should simply be 43). Underscores in the input string are350 /// not allowed (e.g. 0x43 should simply be 43). Underscores in the input string are
330 /// ignored and can be used as digit separators.351 /// ignored and can be used as digit separators.
331 ///352 ///
332 /// Asserts there is enough memory for the value in `self.limbs`. An upper bound on number of limbs can353 /// There must be enough memory for the value in `self.limbs`. An upper bound on number of limbs can
333 /// be determined with `calcSetStringLimbCount`.354 /// be determined with `calcSetStringLimbCount`.
334 /// Asserts the base is in the range [2, 36].355 /// Asserts the base is in the range [2, 36].
335 ///356 ///
336 /// Returns an error if the value has invalid digits for the requested base.357 /// Returns an error if the value has invalid digits for the requested base.
337 ///
338 /// `limbs_buffer` is used for temporary storage. The size required can be found with
339 /// `calcSetStringLimbsBufferLen`.
340 ///
341 /// If `allocator` is provided, it will be used for temporary storage to improve
342 /// multiplication performance. `error.OutOfMemory` is handled with a fallback algorithm.
343 pub fn setString(358 pub fn setString(
344 self: *Mutable,359 self: *Mutable,
345 base: u8,360 base: u8,
346 value: []const u8,361 value: []const u8,
347 limbs_buffer: []Limb,
348 allocator: ?Allocator,
349 ) error{InvalidCharacter}!void {362 ) error{InvalidCharacter}!void {
350 assert(base >= 2);363 assert(base >= 2);
351 assert(base <= 36);364 assert(base <= 36);
...@@ -357,18 +370,41 @@ pub const Mutable = struct {...@@ -357,18 +370,41 @@ pub const Mutable = struct {
357 i += 1;370 i += 1;
358 }371 }
359372
360 const ap_base: Const = .{ .limbs = &[_]Limb{base}, .positive = true };373 @memset(self.limbs, 0);
361 self.set(0);374 self.len = 1;
362375
376 var limb: Limb = 0;
377 var j: usize = 0;
363 for (value[i..]) |ch| {378 for (value[i..]) |ch| {
364 if (ch == '_') {379 if (ch == '_') {
365 continue;380 continue;
366 }381 }
367 const d = try std.fmt.charToDigit(ch, base);382 const d = try std.fmt.charToDigit(ch, base);
368 const ap_d: Const = .{ .limbs = &[_]Limb{d}, .positive = true };383 limb *= base;
369384 limb += d;
370 self.mul(self.toConst(), ap_base, limbs_buffer, allocator);385 j += 1;
371 self.add(self.toConst(), ap_d);386
387 if (j == constants.digits_per_limb[base]) {
388 const len = @min(self.len + 1, self.limbs.len);
389 // r = a * b = a + a * (b - 1)
390 // we assert when self.limbs is not large enough to store the number
391 assert(!llmulLimb(.add, self.limbs[0..len], self.limbs[0..len], constants.big_bases[base] - 1));
392 assert(lladdcarry(self.limbs[0..len], self.limbs[0..len], &[1]Limb{limb}) == 0);
393
394 if (self.limbs.len > self.len and self.limbs[self.len] != 0)
395 self.len += 1;
396 j = 0;
397 limb = 0;
398 }
399 }
400 if (j > 0) {
401 const len = @min(self.len + 1, self.limbs.len);
402 // we assert when self.limbs is not large enough to store the number
403 assert(!llmulLimb(.add, self.limbs[0..len], self.limbs[0..len], math.pow(Limb, base, j) - 1));
404 assert(lladdcarry(self.limbs[0..len], self.limbs[0..len], &[1]Limb{limb}) == 0);
405
406 if (self.limbs.len > self.len and self.limbs[self.len] != 0)
407 self.len += 1;
372 }408 }
373 self.positive = positive;409 self.positive = positive;
374 }410 }
...@@ -2081,7 +2117,7 @@ pub const Const = struct {...@@ -2081,7 +2117,7 @@ pub const Const = struct {
2081 for (self.limbs[0..self.limbs.len]) |limb| {2117 for (self.limbs[0..self.limbs.len]) |limb| {
2082 std.debug.print("{x} ", .{limb});2118 std.debug.print("{x} ", .{limb});
2083 }2119 }
2084 std.debug.print("len={} positive={}\n", .{ self.len, self.positive });2120 std.debug.print("len={} positive={}\n", .{ self.limbs.len, self.positive });
2085 }2121 }
20862122
2087 pub fn abs(self: Const) Const {2123 pub fn abs(self: Const) Const {
...@@ -2884,10 +2920,8 @@ pub const Managed = struct {...@@ -2884,10 +2920,8 @@ pub const Managed = struct {
2884 pub fn setString(self: *Managed, base: u8, value: []const u8) !void {2920 pub fn setString(self: *Managed, base: u8, value: []const u8) !void {
2885 if (base < 2 or base > 36) return error.InvalidBase;2921 if (base < 2 or base > 36) return error.InvalidBase;
2886 try self.ensureCapacity(calcSetStringLimbCount(base, value.len));2922 try self.ensureCapacity(calcSetStringLimbCount(base, value.len));
2887 const limbs_buffer = try self.allocator.alloc(Limb, calcSetStringLimbsBufferLen(base, value.len));
2888 defer self.allocator.free(limbs_buffer);
2889 var m = self.toMutable();2923 var m = self.toMutable();
2890 try m.setString(base, value, limbs_buffer, self.allocator);2924 try m.setString(base, value);
2891 self.setMetadata(m.positive, m.len);2925 self.setMetadata(m.positive, m.len);
2892 }2926 }
28932927
...@@ -3596,6 +3630,7 @@ fn llmulaccKaratsuba(...@@ -3596,6 +3630,7 @@ fn llmulaccKaratsuba(
3596/// r = r (op) a.3630/// r = r (op) a.
3597/// The result is computed modulo `r.len`.3631/// The result is computed modulo `r.len`.
3598fn llaccum(comptime op: AccOp, r: []Limb, a: []const Limb) void {3632fn llaccum(comptime op: AccOp, r: []Limb, a: []const Limb) void {
3633 assert(!slicesOverlap(r, a) or @intFromPtr(r.ptr) <= @intFromPtr(a.ptr));
3599 if (op == .sub) {3634 if (op == .sub) {
3600 _ = llsubcarry(r, r, a);3635 _ = llsubcarry(r, r, a);
3601 return;3636 return;
...@@ -3665,6 +3700,8 @@ fn llmulaccLong(comptime op: AccOp, r: []Limb, a: []const Limb, b: []const Limb)...@@ -3665,6 +3700,8 @@ fn llmulaccLong(comptime op: AccOp, r: []Limb, a: []const Limb, b: []const Limb)
3665/// The result is computed modulo `r.len`.3700/// The result is computed modulo `r.len`.
3666/// Returns whether the operation overflowed.3701/// Returns whether the operation overflowed.
3667fn llmulLimb(comptime op: AccOp, acc: []Limb, y: []const Limb, xi: Limb) bool {3702fn llmulLimb(comptime op: AccOp, acc: []Limb, y: []const Limb, xi: Limb) bool {
3703 assert(!slicesOverlap(acc, y) or @intFromPtr(acc.ptr) <= @intFromPtr(y.ptr));
3704
3668 if (xi == 0) {3705 if (xi == 0) {
3669 return false;3706 return false;
3670 }3707 }
...@@ -3727,6 +3764,8 @@ fn llsubcarry(r: []Limb, a: []const Limb, b: []const Limb) Limb {...@@ -3727,6 +3764,8 @@ fn llsubcarry(r: []Limb, a: []const Limb, b: []const Limb) Limb {
3727 assert(a.len != 0 and b.len != 0);3764 assert(a.len != 0 and b.len != 0);
3728 assert(a.len >= b.len);3765 assert(a.len >= b.len);
3729 assert(r.len >= a.len);3766 assert(r.len >= a.len);
3767 assert(!slicesOverlap(r, a) or @intFromPtr(r.ptr) <= @intFromPtr(a.ptr));
3768 assert(!slicesOverlap(r, b) or @intFromPtr(r.ptr) <= @intFromPtr(b.ptr));
37303769
3731 var i: usize = 0;3770 var i: usize = 0;
3732 var borrow: Limb = 0;3771 var borrow: Limb = 0;
...@@ -3758,6 +3797,8 @@ fn lladdcarry(r: []Limb, a: []const Limb, b: []const Limb) Limb {...@@ -3758,6 +3797,8 @@ fn lladdcarry(r: []Limb, a: []const Limb, b: []const Limb) Limb {
3758 assert(a.len != 0 and b.len != 0);3797 assert(a.len != 0 and b.len != 0);
3759 assert(a.len >= b.len);3798 assert(a.len >= b.len);
3760 assert(r.len >= a.len);3799 assert(r.len >= a.len);
3800 assert(!slicesOverlap(r, a) or @intFromPtr(r.ptr) <= @intFromPtr(a.ptr));
3801 assert(!slicesOverlap(r, b) or @intFromPtr(r.ptr) <= @intFromPtr(b.ptr));
37613802
3762 var i: usize = 0;3803 var i: usize = 0;
3763 var carry: Limb = 0;3804 var carry: Limb = 0;
lib/std/math/big/int_test.zig+24-24
...@@ -737,7 +737,7 @@ test "string to" {...@@ -737,7 +737,7 @@ test "string to" {
737 defer testing.allocator.free(as);737 defer testing.allocator.free(as);
738 const es = "120317241209124781241290847124";738 const es = "120317241209124781241290847124";
739739
740 try testing.expect(mem.eql(u8, as, es));740 try testing.expectEqualSlices(u8, es, as);
741}741}
742742
743test "string to base base error" {743test "string to base base error" {
...@@ -755,7 +755,7 @@ test "string to base 2" {...@@ -755,7 +755,7 @@ test "string to base 2" {
755 defer testing.allocator.free(as);755 defer testing.allocator.free(as);
756 const es = "-1011";756 const es = "-1011";
757757
758 try testing.expect(mem.eql(u8, as, es));758 try testing.expectEqualSlices(u8, es, as);
759}759}
760760
761test "string to base 16" {761test "string to base 16" {
...@@ -766,7 +766,7 @@ test "string to base 16" {...@@ -766,7 +766,7 @@ test "string to base 16" {
766 defer testing.allocator.free(as);766 defer testing.allocator.free(as);
767 const es = "efffffff00000001eeeeeeefaaaaaaab";767 const es = "efffffff00000001eeeeeeefaaaaaaab";
768768
769 try testing.expect(mem.eql(u8, as, es));769 try testing.expectEqualSlices(u8, es, as);
770}770}
771771
772test "string to base 36" {772test "string to base 36" {
...@@ -777,7 +777,7 @@ test "string to base 36" {...@@ -777,7 +777,7 @@ test "string to base 36" {
777 defer testing.allocator.free(as);777 defer testing.allocator.free(as);
778 const es = "fifvthrv1mzt79ez9";778 const es = "fifvthrv1mzt79ez9";
779779
780 try testing.expect(mem.eql(u8, as, es));780 try testing.expectEqualSlices(u8, es, as);
781}781}
782782
783test "neg string to" {783test "neg string to" {
...@@ -788,7 +788,7 @@ test "neg string to" {...@@ -788,7 +788,7 @@ test "neg string to" {
788 defer testing.allocator.free(as);788 defer testing.allocator.free(as);
789 const es = "-123907434";789 const es = "-123907434";
790790
791 try testing.expect(mem.eql(u8, as, es));791 try testing.expectEqualSlices(u8, es, as);
792}792}
793793
794test "zero string to" {794test "zero string to" {
...@@ -799,7 +799,7 @@ test "zero string to" {...@@ -799,7 +799,7 @@ test "zero string to" {
799 defer testing.allocator.free(as);799 defer testing.allocator.free(as);
800 const es = "0";800 const es = "0";
801801
802 try testing.expect(mem.eql(u8, as, es));802 try testing.expectEqualSlices(u8, es, as);
803}803}
804804
805test "clone" {805test "clone" {
...@@ -3404,26 +3404,26 @@ test "big int conversion read twos complement with padding" {...@@ -3404,26 +3404,26 @@ test "big int conversion read twos complement with padding" {
34043404
3405 var bit_count: usize = 12 * 8 + 1;3405 var bit_count: usize = 12 * 8 + 1;
3406 a.toConst().writeTwosComplement(buffer1[0..13], .little);3406 a.toConst().writeTwosComplement(buffer1[0..13], .little);
3407 try testing.expect(std.mem.eql(u8, buffer1, &[_]u8{ 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0xaa, 0xaa, 0xaa }));3407 try testing.expectEqualSlices(u8, &[_]u8{ 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0xaa, 0xaa, 0xaa }, buffer1);
3408 a.toConst().writeTwosComplement(buffer1[0..13], .big);3408 a.toConst().writeTwosComplement(buffer1[0..13], .big);
3409 try testing.expect(std.mem.eql(u8, buffer1, &[_]u8{ 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xaa, 0xaa, 0xaa }));3409 try testing.expectEqualSlices(u8, &[_]u8{ 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xaa, 0xaa, 0xaa }, buffer1);
3410 a.toConst().writeTwosComplement(buffer1[0..16], .little);3410 a.toConst().writeTwosComplement(buffer1[0..16], .little);
3411 try testing.expect(std.mem.eql(u8, buffer1, &[_]u8{ 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0, 0x0, 0x0 }));3411 try testing.expectEqualSlices(u8, &[_]u8{ 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0, 0x0, 0x0 }, buffer1);
3412 a.toConst().writeTwosComplement(buffer1[0..16], .big);3412 a.toConst().writeTwosComplement(buffer1[0..16], .big);
3413 try testing.expect(std.mem.eql(u8, buffer1, &[_]u8{ 0x0, 0x0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd }));3413 try testing.expectEqualSlices(u8, &[_]u8{ 0x0, 0x0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd }, buffer1);
34143414
3415 @memset(buffer1, 0xaa);3415 @memset(buffer1, 0xaa);
3416 try a.set(-0x01_02030405_06070809_0a0b0c0d);3416 try a.set(-0x01_02030405_06070809_0a0b0c0d);
3417 bit_count = 12 * 8 + 2;3417 bit_count = 12 * 8 + 2;
34183418
3419 a.toConst().writeTwosComplement(buffer1[0..13], .little);3419 a.toConst().writeTwosComplement(buffer1[0..13], .little);
3420 try testing.expect(std.mem.eql(u8, buffer1, &[_]u8{ 0xf3, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xaa, 0xaa, 0xaa }));3420 try testing.expectEqualSlices(u8, &[_]u8{ 0xf3, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xaa, 0xaa, 0xaa }, buffer1);
3421 a.toConst().writeTwosComplement(buffer1[0..13], .big);3421 a.toConst().writeTwosComplement(buffer1[0..13], .big);
3422 try testing.expect(std.mem.eql(u8, buffer1, &[_]u8{ 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf3, 0xaa, 0xaa, 0xaa }));3422 try testing.expectEqualSlices(u8, &[_]u8{ 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf3, 0xaa, 0xaa, 0xaa }, buffer1);
3423 a.toConst().writeTwosComplement(buffer1[0..16], .little);3423 a.toConst().writeTwosComplement(buffer1[0..16], .little);
3424 try testing.expect(std.mem.eql(u8, buffer1, &[_]u8{ 0xf3, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0xff, 0xff }));3424 try testing.expectEqualSlices(u8, &[_]u8{ 0xf3, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0xff, 0xff }, buffer1);
3425 a.toConst().writeTwosComplement(buffer1[0..16], .big);3425 a.toConst().writeTwosComplement(buffer1[0..16], .big);
3426 try testing.expect(std.mem.eql(u8, buffer1, &[_]u8{ 0xff, 0xff, 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf3 }));3426 try testing.expectEqualSlices(u8, &[_]u8{ 0xff, 0xff, 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf3 }, buffer1);
3427}3427}
34283428
3429test "big int write twos complement +/- zero" {3429test "big int write twos complement +/- zero" {
...@@ -3438,13 +3438,13 @@ test "big int write twos complement +/- zero" {...@@ -3438,13 +3438,13 @@ test "big int write twos complement +/- zero" {
3438 // Test zero3438 // Test zero
34393439
3440 m.toConst().writeTwosComplement(buffer1[0..13], .little);3440 m.toConst().writeTwosComplement(buffer1[0..13], .little);
3441 try testing.expect(std.mem.eql(u8, buffer1, &(([_]u8{0} ** 13) ++ ([_]u8{0xaa} ** 3))));3441 try testing.expectEqualSlices(u8, &(([_]u8{0} ** 13) ++ ([_]u8{0xaa} ** 3)), buffer1);
3442 m.toConst().writeTwosComplement(buffer1[0..13], .big);3442 m.toConst().writeTwosComplement(buffer1[0..13], .big);
3443 try testing.expect(std.mem.eql(u8, buffer1, &(([_]u8{0} ** 13) ++ ([_]u8{0xaa} ** 3))));3443 try testing.expectEqualSlices(u8, &(([_]u8{0} ** 13) ++ ([_]u8{0xaa} ** 3)), buffer1);
3444 m.toConst().writeTwosComplement(buffer1[0..16], .little);3444 m.toConst().writeTwosComplement(buffer1[0..16], .little);
3445 try testing.expect(std.mem.eql(u8, buffer1, &(([_]u8{0} ** 16))));3445 try testing.expectEqualSlices(u8, &(([_]u8{0} ** 16)), buffer1);
3446 m.toConst().writeTwosComplement(buffer1[0..16], .big);3446 m.toConst().writeTwosComplement(buffer1[0..16], .big);
3447 try testing.expect(std.mem.eql(u8, buffer1, &(([_]u8{0} ** 16))));3447 try testing.expectEqualSlices(u8, &(([_]u8{0} ** 16)), buffer1);
34483448
3449 @memset(buffer1, 0xaa);3449 @memset(buffer1, 0xaa);
3450 m.positive = false;3450 m.positive = false;
...@@ -3452,13 +3452,13 @@ test "big int write twos complement +/- zero" {...@@ -3452,13 +3452,13 @@ test "big int write twos complement +/- zero" {
3452 // Test negative zero3452 // Test negative zero
34533453
3454 m.toConst().writeTwosComplement(buffer1[0..13], .little);3454 m.toConst().writeTwosComplement(buffer1[0..13], .little);
3455 try testing.expect(std.mem.eql(u8, buffer1, &(([_]u8{0} ** 13) ++ ([_]u8{0xaa} ** 3))));3455 try testing.expectEqualSlices(u8, &(([_]u8{0} ** 13) ++ ([_]u8{0xaa} ** 3)), buffer1);
3456 m.toConst().writeTwosComplement(buffer1[0..13], .big);3456 m.toConst().writeTwosComplement(buffer1[0..13], .big);
3457 try testing.expect(std.mem.eql(u8, buffer1, &(([_]u8{0} ** 13) ++ ([_]u8{0xaa} ** 3))));3457 try testing.expectEqualSlices(u8, &(([_]u8{0} ** 13) ++ ([_]u8{0xaa} ** 3)), buffer1);
3458 m.toConst().writeTwosComplement(buffer1[0..16], .little);3458 m.toConst().writeTwosComplement(buffer1[0..16], .little);
3459 try testing.expect(std.mem.eql(u8, buffer1, &(([_]u8{0} ** 16))));3459 try testing.expectEqualSlices(u8, &(([_]u8{0} ** 16)), buffer1);
3460 m.toConst().writeTwosComplement(buffer1[0..16], .big);3460 m.toConst().writeTwosComplement(buffer1[0..16], .big);
3461 try testing.expect(std.mem.eql(u8, buffer1, &(([_]u8{0} ** 16))));3461 try testing.expectEqualSlices(u8, &(([_]u8{0} ** 16)), buffer1);
3462}3462}
34633463
3464test "big int conversion write twos complement with padding" {3464test "big int conversion write twos complement with padding" {
...@@ -3816,7 +3816,7 @@ test "(BigInt) positive" {...@@ -3816,7 +3816,7 @@ test "(BigInt) positive" {
38163816
3817 const b_fmt = try std.fmt.allocPrint(testing.allocator, "{d}", .{b});3817 const b_fmt = try std.fmt.allocPrint(testing.allocator, "{d}", .{b});
3818 defer testing.allocator.free(b_fmt);3818 defer testing.allocator.free(b_fmt);
3819 try testing.expect(!mem.eql(u8, b_fmt, "(BigInt)"));3819 try testing.expect(!mem.eql(u8, "(BigInt)", b_fmt));
3820}3820}
38213821
3822test "(BigInt) negative" {3822test "(BigInt) negative" {
...@@ -3840,7 +3840,7 @@ test "(BigInt) negative" {...@@ -3840,7 +3840,7 @@ test "(BigInt) negative" {
3840 const b_fmt = try std.fmt.allocPrint(testing.allocator, "{d}", .{b});3840 const b_fmt = try std.fmt.allocPrint(testing.allocator, "{d}", .{b});
3841 defer testing.allocator.free(b_fmt);3841 defer testing.allocator.free(b_fmt);
38423842
3843 try testing.expect(mem.eql(u8, a_fmt, "(BigInt)"));3843 try testing.expectEqualSlices(u8, "(BigInt)", a_fmt);
3844 try testing.expect(!mem.eql(u8, b_fmt, "(BigInt)"));3844 try testing.expect(!mem.eql(u8, b_fmt, "(BigInt)"));
3845}3845}
38463846