@@ -1236,7 +1236,9 @@ pub const Mutable = struct {
1236
1236
/// r may alias with a or b.
1237
1237
///
1238
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
1242
/// If a and b are negative, the upper bound is `@max(a.limbs.len, b.limbs.len) + 1`.
1241
1243
pub fn bitAnd (r : * Mutable , a : Const , b : Const ) void {
1242
1244
// Trivial cases, llsignedand does not support zero.
@@ -1250,10 +1252,10 @@ pub const Mutable = struct {
1250
1252
1251
1253
if (a .limbs .len >= b .limbs .len ) {
1252
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
1256
} else {
1255
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
3138
3137
3139
/// r = a & b
3138
3140
pub fn bitAnd (r : * Managed , a : * const Managed , b : * const Managed ) ! void {
3139
- const cap = if (a .isPositive () or b .isPositive ())
3140
- @min ( a . len (), b .len ())
3141
- else
3142
- @max ( a . len (), b . len ()) + 1 ;
3141
+ const cap = if (a .len () >= b .len ())
3142
+ if ( b . isPositive ()) b .len () else if ( a . isPositive ()) a . len () else a . len () + 1
3143
+ else if ( a . isPositive ()) a . len () else if ( b . isPositive ()) b . len () else b . len () + 1 ;
3144
+
3143
3145
try r .ensureCapacity (cap );
3144
3146
var m = r .toMutable ();
3145
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
3887
// x & ~a can only clear bits, so (x & ~a) <= x, meaning (-b - 1) + 1 never overflows.
3886
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
3891
// Omit setting the upper bytes, just deal with those when calling llsignedor.
3890
3892
3891
3893
return false ;
@@ -3922,7 +3924,7 @@ fn llsignedor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_p
3922
3924
// for x = a - 1 and y = b - 1, the +1 term would never cause an overflow.
3923
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
3928
// Omit setting the upper bytes, just deal with those when calling llsignedor.
3927
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
3934
// r may alias.
3933
3935
// a and b must not be 0.
3934
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.
3936
- // When both a and b are negative, r requires at least `a.limbs.len + 1` limbs of storage.
3937
+ // We assume `a.len >= b.len` here, so:
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
3941
fn llsignedand (r : []Limb , a : []const Limb , a_positive : bool , b : []const Limb , b_positive : bool ) bool {
3938
3942
@setRuntimeSafety (debug_safety );
3939
3943
assert (a .len != 0 and b .len != 0 );
3940
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
3947
if (a_positive and b_positive ) {
3944
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
3991
3988
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
3991
- // the upper bytes are zero. Omit setting them here and simply discard
3992
- // them whenever llsignedand is called.
3994
+ // With b = 0 and b_borrow = 0 we have a & ~(0 - 0) = a & ~0 = a, so
3995
+ // the upper bytes are the same as those of a.
3996
+
3997
+ while (i < a .len ) : (i += 1 ) {
3998
+ r [i ] = a [i ];
3999
+ }
3993
4000
3994
4001
return true ;
3995
4002
} else {
@@ -4017,7 +4024,7 @@ fn llsignedand(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_
4017
4024
// b is at least 1, so this should never underflow.
4018
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
4028
while (i < a .len ) : (i += 1 ) {
4022
4029
const ov1 = @subWithOverflow (a [i ], a_borrow );
4023
4030
a_borrow = ov1 [1 ];
0 commit comments