| ... | @@ -454,6 +454,7 @@ pub const Mutable = struct { | ... | @@ -454,6 +454,7 @@ pub const Mutable = struct { |
| 454 | // - We overflowed req_limbs. In this case, the carry is ignored, as it would be removed by | 454 | // - We overflowed req_limbs. In this case, the carry is ignored, as it would be removed by |
| 455 | // truncate anyway. | 455 | // truncate anyway. |
| 456 | // - a and b had less elements than req_limbs, and those were overflowed. This case needs to be handled. | 456 | // - a and b had less elements than req_limbs, and those were overflowed. This case needs to be handled. |
| | 457 | // Note: after this we still might need to wrap. |
| 457 | const msl = math.max(a.limbs.len, b.limbs.len); | 458 | const msl = math.max(a.limbs.len, b.limbs.len); |
| 458 | if (msl < req_limbs) { | 459 | if (msl < req_limbs) { |
| 459 | r.limbs[msl] = 1; | 460 | r.limbs[msl] = 1; |
| ... | @@ -464,6 +465,48 @@ pub const Mutable = struct { | ... | @@ -464,6 +465,48 @@ pub const Mutable = struct { |
| 464 | r.truncate(r.toConst(), signedness, bit_count); | 465 | r.truncate(r.toConst(), signedness, bit_count); |
| 465 | } | 466 | } |
| 466 | | 467 | |
| | 468 | /// r = a + b with 2s-complement saturating semantics. |
| | 469 | /// r, a and b may be aliases. |
| | 470 | /// |
| | 471 | /// Assets the result fits in `r`. Upper bound on the number of limbs needed by |
| | 472 | /// r is `calcTwosCompLimbCount(bit_count)`. |
| | 473 | pub fn addSat(r: *Mutable, a: Const, b: Const, signedness: std.builtin.Signedness, bit_count: usize) void { |
| | 474 | const req_limbs = calcTwosCompLimbCount(bit_count); |
| | 475 | |
| | 476 | // Slice of the upper bits if they exist, these will be ignored and allows us to use addCarry to determine |
| | 477 | // if an overflow occured. |
| | 478 | const x = Const{ |
| | 479 | .positive = a.positive, |
| | 480 | .limbs = a.limbs[0..math.min(req_limbs, a.limbs.len)], |
| | 481 | }; |
| | 482 | |
| | 483 | const y = Const{ |
| | 484 | .positive = b.positive, |
| | 485 | .limbs = b.limbs[0..math.min(req_limbs, b.limbs.len)], |
| | 486 | }; |
| | 487 | |
| | 488 | if (r.addCarry(x, y)) { |
| | 489 | // There are two possibilities here: |
| | 490 | // - We overflowed req_limbs, in which case we need to saturate. |
| | 491 | // - a and b had less elements than req_limbs, and those were overflowed. |
| | 492 | // Note: In this case, might _also_ need to saturate. |
| | 493 | const msl = math.max(a.limbs.len, b.limbs.len); |
| | 494 | if (msl < req_limbs) { |
| | 495 | r.limbs[msl] = 1; |
| | 496 | r.len = req_limbs; |
| | 497 | // Note: Saturation may still be required if msl == req_limbs - 1 |
| | 498 | } else { |
| | 499 | // Overflowed req_limbs, definitely saturate. |
| | 500 | r.setTwosCompIntLimit(if (r.positive) .max else .min, signedness, bit_count); |
| | 501 | } |
| | 502 | } |
| | 503 | |
| | 504 | // Saturate if the result didn't fit. |
| | 505 | if (!r.toConst().fitsInTwosComp(signedness, bit_count)) { |
| | 506 | r.setTwosCompIntLimit(if (r.positive) .max else .min, signedness, bit_count); |
| | 507 | } |
| | 508 | } |
| | 509 | |
| 467 | /// Base implementation for subtraction. Subtracts `max(a.limbs.len, b.limbs.len)` elements from a and b, | 510 | /// Base implementation for subtraction. Subtracts `max(a.limbs.len, b.limbs.len)` elements from a and b, |
| 468 | /// and returns whether any overflow occured. | 511 | /// and returns whether any overflow occured. |
| 469 | /// r, a and b may be aliases. | 512 | /// r, a and b may be aliases. |
| ... | @@ -559,6 +602,7 @@ pub const Mutable = struct { | ... | @@ -559,6 +602,7 @@ pub const Mutable = struct { |
| 559 | // - We overflowed req_limbs. In this case, the carry is ignored, as it would be removed by | 602 | // - We overflowed req_limbs. In this case, the carry is ignored, as it would be removed by |
| 560 | // truncate anyway. | 603 | // truncate anyway. |
| 561 | // - a and b had less elements than req_limbs, and those were overflowed. This case needs to be handled. | 604 | // - a and b had less elements than req_limbs, and those were overflowed. This case needs to be handled. |
| | 605 | // Note: after this we still might need to wrap. |
| 562 | const msl = math.max(a.limbs.len, b.limbs.len); | 606 | const msl = math.max(a.limbs.len, b.limbs.len); |
| 563 | if (msl < req_limbs) { | 607 | if (msl < req_limbs) { |
| 564 | r.limbs[msl] = 1; | 608 | r.limbs[msl] = 1; |
| ... | @@ -2070,6 +2114,13 @@ pub const Managed = struct { | ... | @@ -2070,6 +2114,13 @@ pub const Managed = struct { |
| 2070 | r.setMetadata(m.positive, m.len); | 2114 | r.setMetadata(m.positive, m.len); |
| 2071 | } | 2115 | } |
| 2072 | | 2116 | |
| | 2117 | pub fn addSat(r: *Managed, a: Const, b: Const, signedness: std.builtin.Signedness, bit_count: usize) Allocator.Error!void { |
| | 2118 | try r.ensureCapacity(calcTwosCompLimbCount(bit_count)); |
| | 2119 | var m = r.toMutable(); |
| | 2120 | m.addSat(a, b, signedness, bit_count); |
| | 2121 | r.setMetadata(m.positive, m.len); |
| | 2122 | } |
| | 2123 | |
| 2073 | /// r = a - b | 2124 | /// r = a - b |
| 2074 | /// | 2125 | /// |
| 2075 | /// r, a and b may be aliases. | 2126 | /// r, a and b may be aliases. |