Commit aa07366513

poypoyan <srazin123@gmail.com>
2024-05-21 15:28:05
std.math.big.int.Managed: adjust size of arg for limbs_buffer in format()
1 parent 33d7815
Changed files (2)
lib
std
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(
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)"));
+}