| ... | @@ -566,15 +566,7 @@ pub const Mutable = struct { | ... | @@ -566,15 +566,7 @@ pub const Mutable = struct { |
| 566 | /// Asserts the result fits in `r`. An upper bound on the number of limbs needed by | 566 | /// Asserts the result fits in `r`. An upper bound on the number of limbs needed by |
| 567 | /// r is `math.max(a.limbs.len, b.limbs.len) + 1`. The +1 is not needed if both operands are positive. | 567 | /// r is `math.max(a.limbs.len, b.limbs.len) + 1`. The +1 is not needed if both operands are positive. |
| 568 | pub fn sub(r: *Mutable, a: Const, b: Const) void { | 568 | pub fn sub(r: *Mutable, a: Const, b: Const) void { |
| 569 | if (r.subCarry(a, b)) { | 569 | r.add(a, b.negate()); |
| 570 | // Fix up the result. Note that addCarry normalizes by a.limbs.len or b.limbs.len, | | |
| 571 | // so we need to set the length here. | | |
| 572 | const msl = math.max(a.limbs.len, b.limbs.len); | | |
| 573 | // `addCarry` normalizes by `msl`, so we need to fix up the result manually here. | | |
| 574 | // Note, the fact that it normalized means that the intermediary limbs are zero here. | | |
| 575 | r.len = msl + 1; | | |
| 576 | r.limbs[msl] = 1; // If this panics, there wasn't enough space in `r`. | | |
| 577 | } | | |
| 578 | } | 570 | } |
| 579 | | 571 | |
| 580 | /// r = a - b with 2s-complement wrapping semantics. | 572 | /// r = a - b with 2s-complement wrapping semantics. |
| ... | @@ -583,34 +575,16 @@ pub const Mutable = struct { | ... | @@ -583,34 +575,16 @@ pub const Mutable = struct { |
| 583 | /// Asserts the result fits in `r`. An upper bound on the number of limbs needed by | 575 | /// Asserts the result fits in `r`. An upper bound on the number of limbs needed by |
| 584 | /// r is `calcTwosCompLimbCount(bit_count)`. | 576 | /// r is `calcTwosCompLimbCount(bit_count)`. |
| 585 | pub fn subWrap(r: *Mutable, a: Const, b: Const, signedness: std.builtin.Signedness, bit_count: usize) void { | 577 | pub fn subWrap(r: *Mutable, a: Const, b: Const, signedness: std.builtin.Signedness, bit_count: usize) void { |
| 586 | const req_limbs = calcTwosCompLimbCount(bit_count); | 578 | r.addWrap(a, b.negate(), signedness, bit_count); |
| 587 | | 579 | } |
| 588 | // Slice of the upper bits if they exist, these will be ignored and allows us to use addCarry to determine | | |
| 589 | // if an overflow occured. | | |
| 590 | const x = Const{ | | |
| 591 | .positive = a.positive, | | |
| 592 | .limbs = a.limbs[0..math.min(req_limbs, a.limbs.len)], | | |
| 593 | }; | | |
| 594 | | | |
| 595 | const y = Const{ | | |
| 596 | .positive = b.positive, | | |
| 597 | .limbs = b.limbs[0..math.min(req_limbs, b.limbs.len)], | | |
| 598 | }; | | |
| 599 | | | |
| 600 | if (r.subCarry(x, y)) { | | |
| 601 | // There are two possibilities here: | | |
| 602 | // - We overflowed req_limbs. In this case, the carry is ignored, as it would be removed by | | |
| 603 | // truncate anyway. | | |
| 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. | | |
| 606 | const msl = math.max(a.limbs.len, b.limbs.len); | | |
| 607 | if (msl < req_limbs) { | | |
| 608 | r.limbs[msl] = 1; | | |
| 609 | r.len = req_limbs; | | |
| 610 | } | | |
| 611 | } | | |
| 612 | | 580 | |
| 613 | r.truncate(r.toConst(), signedness, bit_count); | 581 | /// r = a - b with 2s-complement saturating semantics. |
| | 582 | /// r, a and b may be aliases. |
| | 583 | /// |
| | 584 | /// Assets the result fits in `r`. Upper bound on the number of limbs needed by |
| | 585 | /// r is `calcTwosCompLimbCount(bit_count)`. |
| | 586 | pub fn subSat(r: *Mutable, a: Const, b: Const, signedness: std.builtin.Signedness, bit_count: usize) void { |
| | 587 | r.addSat(a, b.negate(), signedness, bit_count); |
| 614 | } | 588 | } |
| 615 | | 589 | |
| 616 | /// rma = a * b | 590 | /// rma = a * b |
| ... | @@ -2140,6 +2114,13 @@ pub const Managed = struct { | ... | @@ -2140,6 +2114,13 @@ pub const Managed = struct { |
| 2140 | r.setMetadata(m.positive, m.len); | 2114 | r.setMetadata(m.positive, m.len); |
| 2141 | } | 2115 | } |
| 2142 | | 2116 | |
| | 2117 | pub fn subSat(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.subSat(a, b, signedness, bit_count); |
| | 2121 | r.setMetadata(m.positive, m.len); |
| | 2122 | } |
| | 2123 | |
| 2143 | /// rma = a * b | 2124 | /// rma = a * b |
| 2144 | /// | 2125 | /// |
| 2145 | /// rma, a and b may be aliases. However, it is more efficient if rma does not alias a or b. | 2126 | /// rma, a and b may be aliases. However, it is more efficient if rma does not alias a or b. |