diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig index 0a5c3c6ca5..1438d9c990 100644 --- a/lib/std/math/big/int.zig +++ b/lib/std/math/big/int.zig @@ -2201,8 +2201,8 @@ pub const Const = struct { } /// To allow `std.fmt.format` to work with this type. - /// If the integer is larger than `pow(2, 64 * @sizeOf(usize) * 8), this function will fail - /// to print the string, printing "(BigInt)" instead of a number. + /// If the absolute value of integer is greater than or equal to `pow(2, 64 * @sizeOf(usize) * 8)`, + /// this function will fail to print the string, printing "(BigInt)" instead of a number. /// This is because the rendering algorithm requires reversing a string, which requires O(N) memory. /// See `toString` and `toStringAlloc` for a way to print big integers without failure. pub fn format( @@ -2231,13 +2231,11 @@ pub const Const = struct { std.fmt.invalidFmtError(fmt, self); } - var limbs: [128]Limb = undefined; - const needed_limbs = calcDivLimbsBufferLen(self.limbs.len, 1); - if (needed_limbs > limbs.len) + const available_len = 64; + if (self.limbs.len > available_len) return out_stream.writeAll("(BigInt)"); - // This is the inverse of calcDivLimbsBufferLen - const available_len = (limbs.len / 3) - 2; + var limbs: [calcToStringLimbsBufferLen(available_len, base)]Limb = undefined; const biggest: Const = .{ .limbs = &([1]Limb{comptime math.maxInt(Limb)} ** available_len), @@ -2804,8 +2802,8 @@ pub const Managed = struct { } /// To allow `std.fmt.format` to work with `Managed`. - /// If the integer is larger than `pow(2, 64 * @sizeOf(usize) * 8), this function will fail - /// to print the string, printing "(BigInt)" instead of a number. + /// If the absolute value of integer is greater than or equal to `pow(2, 64 * @sizeOf(usize) * 8)`, + /// this function will fail to print the string, printing "(BigInt)" instead of a number. /// This is because the rendering algorithm requires reversing a string, which requires O(N) memory. /// See `toString` and `toStringAlloc` for a way to print big integers without failure. pub fn format( diff --git a/lib/std/math/big/int_test.zig b/lib/std/math/big/int_test.zig index f42d73689b..ecc1770002 100644 --- a/lib/std/math/big/int_test.zig +++ b/lib/std/math/big/int_test.zig @@ -3232,3 +3232,52 @@ test "Managed sqrt(n) succeed with res.bitCountAbs() >= usize bits" { try expected.setString(10, "11663466984815033033"); try std.testing.expectEqual(std.math.Order.eq, expected.order(res)); } + +test "(BigInt) positive" { + var a = try Managed.initSet(testing.allocator, 2); + defer a.deinit(); + + var b = try Managed.init(testing.allocator); + defer b.deinit(); + + var c = try Managed.initSet(testing.allocator, 1); + defer c.deinit(); + + // a = pow(2, 64 * @sizeOf(usize) * 8), b = a - 1 + try a.pow(&a, 64 * @sizeOf(Limb) * 8); + try b.sub(&a, &c); + + const a_fmt = try std.fmt.allocPrintZ(testing.allocator, "{d}", .{a}); + defer testing.allocator.free(a_fmt); + + const b_fmt = try std.fmt.allocPrintZ(testing.allocator, "{d}", .{b}); + defer testing.allocator.free(b_fmt); + + try testing.expect(mem.eql(u8, a_fmt, "(BigInt)")); + try testing.expect(!mem.eql(u8, b_fmt, "(BigInt)")); +} + +test "(BigInt) negative" { + var a = try Managed.initSet(testing.allocator, 2); + defer a.deinit(); + + var b = try Managed.init(testing.allocator); + defer b.deinit(); + + var c = try Managed.initSet(testing.allocator, 1); + defer c.deinit(); + + // a = -pow(2, 64 * @sizeOf(usize) * 8), b = a + 1 + try a.pow(&a, 64 * @sizeOf(Limb) * 8); + a.negate(); + try b.add(&a, &c); + + const a_fmt = try std.fmt.allocPrintZ(testing.allocator, "{d}", .{a}); + defer testing.allocator.free(a_fmt); + + const b_fmt = try std.fmt.allocPrintZ(testing.allocator, "{d}", .{b}); + defer testing.allocator.free(b_fmt); + + try testing.expect(mem.eql(u8, a_fmt, "(BigInt)")); + try testing.expect(!mem.eql(u8, b_fmt, "(BigInt)")); +}