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