feature. See also
. The project being documented here (as the example) is the Zig library itself.
int.llsignedor
fn llsignedor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_positive: bool) bool
File
Code
fn llsignedor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_positive: bool) bool {
assert(r.len >= a.len);
assert(a.len >= b.len);
if (a_positive and b_positive) {
var i: usize = 0;
while (i < b.len) : (i += 1) {
r[i] = a[i] | b[i];
}
while (i < a.len) : (i += 1) {
r[i] = a[i];
}
return true;
} else if (!a_positive and b_positive) {
// r = (--a) | b
// = ~(-a - 1) | b
// = ~(-a - 1) | ~~b
// = ~((-a - 1) & ~b)
// = -(((-a - 1) & ~b) + 1)
var i: usize = 0;
var a_borrow: u1 = 1;
var r_carry: u1 = 1;
while (i < b.len) : (i += 1) {
const ov1 = @subWithOverflow(a[i], a_borrow);
a_borrow = ov1[1];
const ov2 = @addWithOverflow(ov1[0] & ~b[i], r_carry);
r[i] = ov2[0];
r_carry = ov2[1];
}
// all ones, which would require b[i] to be zero. This cannot be when
// b is normalized, so there cannot be a carry here.
// Also, x & ~b can only clear bits, so (x & ~b) <= x, meaning (-a - 1) + 1 never overflows.
assert(r_carry == 0);
// Note, if a_borrow is zero we do not need to compute anything for
// the higher limbs so we can early return here.
while (i < a.len and a_borrow == 1) : (i += 1) {
const ov = @subWithOverflow(a[i], a_borrow);
r[i] = ov[0];
a_borrow = ov[1];
}
assert(a_borrow == 0);
return false;
} else if (a_positive and !b_positive) {
// r = a | (--b)
// = a | ~(-b - 1)
// = ~~a | ~(-b - 1)
// = ~(~a & (-b - 1))
// = -((~a & (-b - 1)) + 1)
var i: usize = 0;
var b_borrow: u1 = 1;
var r_carry: u1 = 1;
while (i < b.len) : (i += 1) {
const ov1 = @subWithOverflow(b[i], b_borrow);
b_borrow = ov1[1];
const ov2 = @addWithOverflow(~a[i] & ov1[0], r_carry);
r[i] = ov2[0];
r_carry = ov2[1];
}
assert(b_borrow == 0);
// x & ~a can only clear bits, so (x & ~a) <= x, meaning (-b - 1) + 1 never overflows.
assert(r_carry == 0);
// Omit setting the upper bytes, just deal with those when calling llsignedor.
return false;
} else {
// r = (--a) | (--b)
// = ~(-a - 1) | ~(-b - 1)
// = ~((-a - 1) & (-b - 1))
// = -(~(~((-a - 1) & (-b - 1))) + 1)
// = -((-a - 1) & (-b - 1) + 1)
var i: usize = 0;
var a_borrow: u1 = 1;
var b_borrow: u1 = 1;
var r_carry: u1 = 1;
while (i < b.len) : (i += 1) {
const ov1 = @subWithOverflow(a[i], a_borrow);
a_borrow = ov1[1];
const ov2 = @subWithOverflow(b[i], b_borrow);
b_borrow = ov2[1];
const ov3 = @addWithOverflow(ov1[0] & ov2[0], r_carry);
r[i] = ov3[0];
r_carry = ov3[1];
}
assert(b_borrow == 0);
// Can never overflow because in order for b_limb to be maxInt(Limb),
// b_borrow would need to equal 1.
// x & y can only clear bits, meaning x & y <= x and x & y <= y. This implies that
// for x = a - 1 and y = b - 1, the +1 term would never cause an overflow.
assert(r_carry == 0);
// Omit setting the upper bytes, just deal with those when calling llsignedor.
return false;
}
}