authorgravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-07-08 01:52:46+02:00
committergravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-07-08 01:52:46+02:00
loge42cb3b2369b3034c15be3a6f0bf519db4baac98
tree7ca2c7826fdcf18c6e33106809c9594ea4d11c98
parentb4c49390434ac1905ed7b962a26db110daafbd15

std.math.big: update divCeil add tests


2 files changed, 61 insertions(+), 14 deletions(-)

lib/std/math/big/int.zig+23-14
......@@ -1260,8 +1260,8 @@ pub const Mutable = struct {
12601260 // If the result is negative then the default truncating division already rounds
12611261 // towards positive infinity, so no adjustment is needed.
12621262 // If the remainder is 0 then the division is exact and no adjustment is needed.
1263 } else if (a.positive) {
1264 // Both positive.
1263 } else {
1264 // Same sign.
12651265 // We have:
12661266 // modCeil(a, b) != 0
12671267 // => @divCeil(a, b) = @divTrunc(a, b) + 1
......@@ -1270,20 +1270,10 @@ pub const Mutable = struct {
12701270 // b * @divCeil(a, b) + modCeil(a, b) = a
12711271 // => b * @divTrunc(a, b) + b + modCeil(a, b) = a
12721272 // => modCeil(a, b) = @rem(a, b) - b
1273 //
1274 // This works for both positive and negative b because b keeps its sign.
12731275 q.addScalar(q.toConst(), 1);
12741276 r.sub(r.toConst(), y.toConst());
1275 } else {
1276 // Both negative.
1277 // We have:
1278 // modCeil(-a, -b) != 0
1279 // => @divCeil(-a, -b) = @divTrunc(-a, -b) + 1
1280 // And:
1281 // -b * @divTrunc(-a, -b) + @rem(-a, -b) = -a
1282 // -b * @divCeil(-a, -b) + modCeil(-a, -b) = -a
1283 // => -b * @divTrunc(-a, -b) - b + modCeil(-a, -b) = -a
1284 // => modCeil(-a, -b) = @rem(-a, -b) + b
1285 q.addScalar(q.toConst(), 1);
1286 r.add(r.toConst(), y.toConst().abs());
12871277 }
12881278 }
12891279
......@@ -3380,6 +3370,25 @@ pub const Managed = struct {
33803370 r.setMetadata(mr.positive, mr.len);
33813371 }
33823372
3373 /// q = a / b (rem r)
3374 ///
3375 /// a / b are ceiled (rounded towards positive infinity).
3376 ///
3377 /// Returns an error if memory could not be allocated.
3378 pub fn divCeil(q: *Managed, r: *Managed, a: *const Managed, b: *const Managed) !void {
3379 const q_alias = limbsAliasDistinct(q, a) or limbsAliasDistinct(q, b);
3380 const r_alias = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b);
3381 try q.ensureAliasAwareCapacity(a.len(), q_alias);
3382 try r.ensureAliasAwareCapacity(b.len(), r_alias);
3383 var mq = q.toMutable();
3384 var mr = r.toMutable();
3385 const limbs_buffer = try q.allocator.alloc(Limb, calcDivLimbsBufferLen(a.len(), b.len()));
3386 defer q.allocator.free(limbs_buffer);
3387 mq.divCeil(&mr, a.toConst(), b.toConst(), limbs_buffer);
3388 q.setMetadata(mq.positive, mq.len);
3389 r.setMetadata(mr.positive, mr.len);
3390 }
3391
33833392 /// q = a / b (rem r)
33843393 ///
33853394 /// a / b are truncated (rounded towards -inf).
lib/std/math/big/int_test.zig+38
......@@ -2127,6 +2127,44 @@ test "div floor positive close to zero" {
21272127 try testing.expectEqual(10, try r.toInt(i32));
21282128}
21292129
2130fn testDivCeil(comptime T: type, u: T, v: T, eq: T, er: T) !void {
2131 var a = try Managed.initSet(testing.allocator, u);
2132 defer a.deinit();
2133 var b = try Managed.initSet(testing.allocator, v);
2134 defer b.deinit();
2135
2136 var q = try Managed.init(testing.allocator);
2137 defer q.deinit();
2138 var r = try Managed.init(testing.allocator);
2139 defer r.deinit();
2140
2141 try Managed.divCeil(&q, &r, &a, &b);
2142
2143 try testing.expectEqual(eq, try q.toInt(T));
2144 try testing.expectEqual(er, try r.toInt(T));
2145}
2146
2147test "div ceil small" {
2148 try testDivCeil(i32, 5, 3, 2, -1);
2149 try testDivCeil(i32, -5, 3, -1, -2);
2150 try testDivCeil(i32, 5, -3, -1, 2);
2151 try testDivCeil(i32, -5, -3, 2, 1);
2152 try testDivCeil(i32, -0x80000000, 1, -0x80000000, 0);
2153}
2154
2155test "div ceil multi-limb" {
2156 {
2157 const a = (@as(i128, 1) << 100) + 3;
2158 const b: i128 = 4;
2159 try testDivCeil(i128, a, b, (1 << 98) + 1, -1);
2160 }
2161 {
2162 const a = -((@as(i128, 1) << 100) + 3);
2163 const b: i128 = 4;
2164 try testDivCeil(i128, a, b, -(1 << 98), -3);
2165 }
2166}
2167
21302168test "div multi-multi with rem" {
21312169 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
21322170