| ... | ... | @@ -1260,8 +1260,8 @@ pub const Mutable = struct { |
| 1260 | 1260 | // If the result is negative then the default truncating division already rounds |
| 1261 | 1261 | // towards positive infinity, so no adjustment is needed. |
| 1262 | 1262 | // 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. |
| 1265 | 1265 | // We have: |
| 1266 | 1266 | // modCeil(a, b) != 0 |
| 1267 | 1267 | // => @divCeil(a, b) = @divTrunc(a, b) + 1 |
| ... | ... | @@ -1270,20 +1270,10 @@ pub const Mutable = struct { |
| 1270 | 1270 | // b * @divCeil(a, b) + modCeil(a, b) = a |
| 1271 | 1271 | // => b * @divTrunc(a, b) + b + modCeil(a, b) = a |
| 1272 | 1272 | // => modCeil(a, b) = @rem(a, b) - b |
| 1273 | // |
| 1274 | // This works for both positive and negative b because b keeps its sign. |
| 1273 | 1275 | q.addScalar(q.toConst(), 1); |
| 1274 | 1276 | 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()); |
| 1287 | 1277 | } |
| 1288 | 1278 | } |
| 1289 | 1279 | |
| ... | ... | @@ -3380,6 +3370,25 @@ pub const Managed = struct { |
| 3380 | 3370 | r.setMetadata(mr.positive, mr.len); |
| 3381 | 3371 | } |
| 3382 | 3372 | |
| 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 | |
| 3383 | 3392 | /// q = a / b (rem r) |
| 3384 | 3393 | /// |
| 3385 | 3394 | /// a / b are truncated (rounded towards -inf). |