| ... | @@ -1236,7 +1236,9 @@ pub const Mutable = struct { | ... | @@ -1236,7 +1236,9 @@ pub const Mutable = struct { |
| 1236 | /// r may alias with a or b. | 1236 | /// r may alias with a or b. |
| 1237 | /// | 1237 | /// |
| 1238 | /// Asserts that r has enough limbs to store the result. | 1238 | /// Asserts that r has enough limbs to store the result. |
| 1239 | /// If a or b is positive, the upper bound is `@min(a.limbs.len, b.limbs.len)`. | 1239 | /// If only a is positive, the upper bound is `a.limbs.len`. |
| | 1240 | /// If only b is positive, the upper bound is `b.limbs.len`. |
| | 1241 | /// If a and b are positive, the upper bound is `@min(a.limbs.len, b.limbs.len)`. |
| 1240 | /// If a and b are negative, the upper bound is `@max(a.limbs.len, b.limbs.len) + 1`. | 1242 | /// If a and b are negative, the upper bound is `@max(a.limbs.len, b.limbs.len) + 1`. |
| 1241 | pub fn bitAnd(r: *Mutable, a: Const, b: Const) void { | 1243 | pub fn bitAnd(r: *Mutable, a: Const, b: Const) void { |
| 1242 | // Trivial cases, llsignedand does not support zero. | 1244 | // Trivial cases, llsignedand does not support zero. |
| ... | @@ -1250,10 +1252,10 @@ pub const Mutable = struct { | ... | @@ -1250,10 +1252,10 @@ pub const Mutable = struct { |
| 1250 | | 1252 | |
| 1251 | if (a.limbs.len >= b.limbs.len) { | 1253 | if (a.limbs.len >= b.limbs.len) { |
| 1252 | r.positive = llsignedand(r.limbs, a.limbs, a.positive, b.limbs, b.positive); | 1254 | r.positive = llsignedand(r.limbs, a.limbs, a.positive, b.limbs, b.positive); |
| 1253 | r.normalize(if (a.positive or b.positive) b.limbs.len else a.limbs.len + 1); | 1255 | r.normalize(if (b.positive) b.limbs.len else if (a.positive) a.limbs.len else a.limbs.len + 1); |
| 1254 | } else { | 1256 | } else { |
| 1255 | r.positive = llsignedand(r.limbs, b.limbs, b.positive, a.limbs, a.positive); | 1257 | r.positive = llsignedand(r.limbs, b.limbs, b.positive, a.limbs, a.positive); |
| 1256 | r.normalize(if (a.positive or b.positive) a.limbs.len else b.limbs.len + 1); | 1258 | r.normalize(if (a.positive) a.limbs.len else if (b.positive) b.limbs.len else b.limbs.len + 1); |
| 1257 | } | 1259 | } |
| 1258 | } | 1260 | } |
| 1259 | | 1261 | |
| ... | @@ -3136,10 +3138,10 @@ pub const Managed = struct { | ... | @@ -3136,10 +3138,10 @@ pub const Managed = struct { |
| 3136 | | 3138 | |
| 3137 | /// r = a & b | 3139 | /// r = a & b |
| 3138 | pub fn bitAnd(r: *Managed, a: *const Managed, b: *const Managed) !void { | 3140 | pub fn bitAnd(r: *Managed, a: *const Managed, b: *const Managed) !void { |
| 3139 | const cap = if (a.isPositive() or b.isPositive()) | 3141 | const cap = if (a.len() >= b.len()) |
| 3140 | @min(a.len(), b.len()) | 3142 | if (b.isPositive()) b.len() else if (a.isPositive()) a.len() else a.len() + 1 |
| 3141 | else | 3143 | else if (a.isPositive()) a.len() else if (b.isPositive()) b.len() else b.len() + 1; |
| 3142 | @max(a.len(), b.len()) + 1; | 3144 | |
| 3143 | try r.ensureCapacity(cap); | 3145 | try r.ensureCapacity(cap); |
| 3144 | var m = r.toMutable(); | 3146 | var m = r.toMutable(); |
| 3145 | m.bitAnd(a.toConst(), b.toConst()); | 3147 | m.bitAnd(a.toConst(), b.toConst()); |
| ... | @@ -3885,7 +3887,7 @@ fn llsignedor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_p | ... | @@ -3885,7 +3887,7 @@ fn llsignedor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_p |
| 3885 | // x & ~a can only clear bits, so (x & ~a) <= x, meaning (-b - 1) + 1 never overflows. | 3887 | // x & ~a can only clear bits, so (x & ~a) <= x, meaning (-b - 1) + 1 never overflows. |
| 3886 | assert(r_carry == 0); | 3888 | assert(r_carry == 0); |
| 3887 | | 3889 | |
| 3888 | // With b = 0 and b_borrow = 0, we get ~a & (-0 - 0) = ~a & 0 = 0. | 3890 | // With b = 0 and b_borrow = 0, we get ~a & (0 - 0) = ~a & 0 = 0. |
| 3889 | // Omit setting the upper bytes, just deal with those when calling llsignedor. | 3891 | // Omit setting the upper bytes, just deal with those when calling llsignedor. |
| 3890 | | 3892 | |
| 3891 | return false; | 3893 | return false; |
| ... | @@ -3922,7 +3924,7 @@ fn llsignedor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_p | ... | @@ -3922,7 +3924,7 @@ fn llsignedor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_p |
| 3922 | // for x = a - 1 and y = b - 1, the +1 term would never cause an overflow. | 3924 | // for x = a - 1 and y = b - 1, the +1 term would never cause an overflow. |
| 3923 | assert(r_carry == 0); | 3925 | assert(r_carry == 0); |
| 3924 | | 3926 | |
| 3925 | // With b = 0 and b_borrow = 0 we get (-a - 1) & (-0 - 0) = (-a - 1) & 0 = 0. | 3927 | // With b = 0 and b_borrow = 0 we get (-a - 1) & (0 - 0) = (-a - 1) & 0 = 0. |
| 3926 | // Omit setting the upper bytes, just deal with those when calling llsignedor. | 3928 | // Omit setting the upper bytes, just deal with those when calling llsignedor. |
| 3927 | return false; | 3929 | return false; |
| 3928 | } | 3930 | } |
| ... | @@ -3932,13 +3934,15 @@ fn llsignedor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_p | ... | @@ -3932,13 +3934,15 @@ fn llsignedor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_p |
| 3932 | // r may alias. | 3934 | // r may alias. |
| 3933 | // a and b must not be 0. | 3935 | // a and b must not be 0. |
| 3934 | // Returns `true` when the result is positive. | 3936 | // Returns `true` when the result is positive. |
| 3935 | // When either or both of a and b are positive, r requires at least `b.len` limbs of storage. | 3937 | // We assume `a.len >= b.len` here, so: |
| 3936 | // When both a and b are negative, r requires at least `a.limbs.len + 1` limbs of storage. | 3938 | // 1. when b is positive, r requires at least `b.len` limbs of storage, |
| | 3939 | // 2. when b is negative but a is positive, r requires at least `a.len` limbs of storage, |
| | 3940 | // 3. when both a and b are negative, r requires at least `a.len + 1` limbs of storage. |
| 3937 | fn llsignedand(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_positive: bool) bool { | 3941 | fn llsignedand(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_positive: bool) bool { |
| 3938 | @setRuntimeSafety(debug_safety); | 3942 | @setRuntimeSafety(debug_safety); |
| 3939 | assert(a.len != 0 and b.len != 0); | 3943 | assert(a.len != 0 and b.len != 0); |
| 3940 | assert(a.len >= b.len); | 3944 | assert(a.len >= b.len); |
| 3941 | assert(r.len >= if (!a_positive and !b_positive) a.len + 1 else b.len); | 3945 | assert(r.len >= if (b_positive) b.len else if (a_positive) a.len else a.len + 1); |
| 3942 | | 3946 | |
| 3943 | if (a_positive and b_positive) { | 3947 | if (a_positive and b_positive) { |
| 3944 | // Trivial case, result is positive. | 3948 | // Trivial case, result is positive. |
| ... | @@ -3987,9 +3991,12 @@ fn llsignedand(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_ | ... | @@ -3987,9 +3991,12 @@ fn llsignedand(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_ |
| 3987 | | 3991 | |
| 3988 | assert(b_borrow == 0); // b was 0 | 3992 | assert(b_borrow == 0); // b was 0 |
| 3989 | | 3993 | |
| 3990 | // With b = 0 and b_borrow = 0 we have a & ~(-0 - 0) = a & 0 = 0, so | 3994 | // With b = 0 and b_borrow = 0 we have a & ~(0 - 0) = a & ~0 = a, so |
| 3991 | // the upper bytes are zero. Omit setting them here and simply discard | 3995 | // the upper bytes are the same as those of a. |
| 3992 | // them whenever llsignedand is called. | 3996 | |
| | 3997 | while (i < a.len) : (i += 1) { |
| | 3998 | r[i] = a[i]; |
| | 3999 | } |
| 3993 | | 4000 | |
| 3994 | return true; | 4001 | return true; |
| 3995 | } else { | 4002 | } else { |
| ... | @@ -4017,7 +4024,7 @@ fn llsignedand(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_ | ... | @@ -4017,7 +4024,7 @@ fn llsignedand(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_ |
| 4017 | // b is at least 1, so this should never underflow. | 4024 | // b is at least 1, so this should never underflow. |
| 4018 | assert(b_borrow == 0); // b was 0 | 4025 | assert(b_borrow == 0); // b was 0 |
| 4019 | | 4026 | |
| 4020 | // With b = 0 and b_borrow = 0 we get (-a - 1) | (-0 - 0) = (-a - 1) | 0 = -a - 1. | 4027 | // With b = 0 and b_borrow = 0 we get (-a - 1) | (0 - 0) = (-a - 1) | 0 = -a - 1. |
| 4021 | while (i < a.len) : (i += 1) { | 4028 | while (i < a.len) : (i += 1) { |
| 4022 | const ov1 = @subWithOverflow(a[i], a_borrow); | 4029 | const ov1 = @subWithOverflow(a[i], a_borrow); |
| 4023 | a_borrow = ov1[1]; | 4030 | a_borrow = ov1[1]; |