Two's complement subtraction and overflow
Subtraction
TheoremSubtraction by addition#✓fully proved
Let \(x\) and \(y\) be \(n\)-bit words and let \(\bar y\) be the bitwise complement of \(y\). Adding \(x\) and \(\bar y\) with carry in \(1\) gives the \(n\)-bit result \(x - y\) (the difference modulo \(2^n\)), and the carry out is \(1\) exactly when there is no unsigned borrow, that is, when \(y \le x\) as unsigned integers.
theorem adc_not_true : BitVec.adc x (~~~y) true = (!x.usubOverflow y, x - y)
TheoremThe ripple-carry adder subtracts#✓fully proved
Let \(x\) and \(y\) be \(n\)-bit words and let \(\bar y\) be the bitwise complement of \(y\). Evaluate the \(n\)-bit ripple-carry adder, with XOR, AND and OR gates, on the bits of \(x\), the bits of \(\bar y\) and carry in \(1\). Then for every \(i < n\), output \(i\) is bit \(i\) (counting from the least significant bit \(0\)) of \(x - y\) modulo \(2^n\).
theorem rippleCarryAdder_sub (i : ℕ) (hi : i < n) :
(rippleCarryAdder n).eval arithInterpretation (rcaInput x (~~~y) true) ⟨i, by omega⟩ =
(x - y).getLsbD i
def rippleCarryAdder (n : ℕ) : Circuit arithSignature (2 * n + 1) (n + 1) where
size := 5 * n
program := rcaProgram n (5 * n) (Nat.le_refl _)
outputs o := if h : o.val < n then Wire.gate ⟨5 * o.val + 1, by omega⟩
else carryWire n (5 * n) n (Nat.le_refl _)
CSLibExt/Computability/Circuit/Arithmetic/RippleCarry.lean:121
def arithInterpretation : Interpretation arithSignature Bool
| .xor, f => f ⟨0, by decide⟩ ^^ f ⟨1, by decide⟩
| .and, f => f ⟨0, by decide⟩ && f ⟨1, by decide⟩
| .or, f => f ⟨0, by decide⟩ || f ⟨1, by decide⟩
CSLibExt/Computability/Circuit/Arithmetic/RippleCarry.lean:63
def rcaInput {n : ℕ} (x y : BitVec n) (c : Bool) : Fin (2 * n + 1) → Bool := fun j =>
if j.val < n then x.getLsbD j.val else if j.val < 2 * n then y.getLsbD (j.val - n) else c
CSLibExt/Computability/Circuit/Arithmetic/RippleCarry.lean:128
Uses 6
TheoremCarry out of ripple-carry subtraction#✓fully proved
Let \(x\) and \(y\) be \(n\)-bit words and let \(\bar y\) be the bitwise complement of \(y\). Evaluate the \(n\)-bit ripple-carry adder, with XOR, AND and OR gates, on the bits of \(x\), the bits of \(\bar y\) and carry in \(1\). Its carry out (output \(n\)) is \(1\) exactly when there is no unsigned borrow in \(x - y\), that is, when \(y \le x\) as unsigned integers.
theorem rippleCarryAdder_noBorrow :
(rippleCarryAdder n).eval arithInterpretation (rcaInput x (~~~y) true) ⟨n, by omega⟩ =
!x.usubOverflow y
def rippleCarryAdder (n : ℕ) : Circuit arithSignature (2 * n + 1) (n + 1) where
size := 5 * n
program := rcaProgram n (5 * n) (Nat.le_refl _)
outputs o := if h : o.val < n then Wire.gate ⟨5 * o.val + 1, by omega⟩
else carryWire n (5 * n) n (Nat.le_refl _)
CSLibExt/Computability/Circuit/Arithmetic/RippleCarry.lean:121
def arithInterpretation : Interpretation arithSignature Bool
| .xor, f => f ⟨0, by decide⟩ ^^ f ⟨1, by decide⟩
| .and, f => f ⟨0, by decide⟩ && f ⟨1, by decide⟩
| .or, f => f ⟨0, by decide⟩ || f ⟨1, by decide⟩
CSLibExt/Computability/Circuit/Arithmetic/RippleCarry.lean:63
def rcaInput {n : ℕ} (x y : BitVec n) (c : Bool) : Fin (2 * n + 1) → Bool := fun j =>
if j.val < n then x.getLsbD j.val else if j.val < 2 * n then y.getLsbD (j.val - n) else c
CSLibExt/Computability/Circuit/Arithmetic/RippleCarry.lean:128
Uses 6
TheoremThe carry-lookahead adder subtracts#✓fully proved
Let \(x\) and \(y\) be \(n\)-bit words, let \(\bar y\) be the bitwise complement of \(y\), and let \(K\) satisfy \(n \le 2^K\). Evaluate the \(n\)-bit carry-lookahead adder with \(K\) levels, with XOR, AND and OR gates, on the bits of \(x\), the bits of \(\bar y\) and carry in \(1\). Then for every \(i < n\), output \(i\) is bit \(i\) (counting from the least significant bit \(0\)) of \(x - y\) modulo \(2^n\).
theorem carryLookaheadAdder_sub {K : ℕ} (hK : n ≤ 2 ^ K) (i : ℕ) (hi : i < n) :
(carryLookaheadAdder n K).eval arithInterpretation (rcaInput x (~~~y) true)
⟨i, by omega⟩ = (x - y).getLsbD i
def carryLookaheadAdder (n K : ℕ) :
Circuit arithSignature (2 * n + 1) (n + 1) where
size := levelBase n K + 3 * n
program := claProgram n K
outputs o :=
if h : o.val < n then Wire.gate ⟨levelBase n K + (3 * o.val + 2), by omega⟩
else if h' : n = 0 then Wire.input ⟨2 * n, by omega⟩
else Wire.gate ⟨levelBase n K + (3 * (n - 1) + 1), by omega⟩
CSLibExt/Computability/Circuit/Arithmetic/CarryLookahead.lean:285
def arithInterpretation : Interpretation arithSignature Bool
| .xor, f => f ⟨0, by decide⟩ ^^ f ⟨1, by decide⟩
| .and, f => f ⟨0, by decide⟩ && f ⟨1, by decide⟩
| .or, f => f ⟨0, by decide⟩ || f ⟨1, by decide⟩
CSLibExt/Computability/Circuit/Arithmetic/RippleCarry.lean:63
def rcaInput {n : ℕ} (x y : BitVec n) (c : Bool) : Fin (2 * n + 1) → Bool := fun j =>
if j.val < n then x.getLsbD j.val else if j.val < 2 * n then y.getLsbD (j.val - n) else c
CSLibExt/Computability/Circuit/Arithmetic/RippleCarry.lean:128
Signed overflow
TheoremSigned overflow is the XOR of the last two carries#✓fully proved
Let \(n \ge 1\) and let \(x\) and \(y\) be \(n\)-bit words. The two's complement addition \(x + y\) overflows (the sum of the two's complement values of \(x\) and \(y\) is at least \(2^{n-1}\) or less than \(-2^{n-1}\)) exactly when the carry into the sign bit \(n - 1\) differs from the carry out of it, both carries taken when adding \(x\) and \(y\) with carry in \(0\).
theorem saddOverflow_eq_carry_xor (hn : 0 < n) :
x.saddOverflow y = (BitVec.carry (n - 1) x y false ^^ BitVec.carry n x y false)
Used by 1
DefinitionThe overflow adder#✓fully proved
The \(n\)-bit overflow adder is the \(n\)-bit ripple-carry adder with one extra XOR gate. It has the same \(2n + 1\) inputs (the bits of the two summands, then the carry in) and \(5n + 1\) gates: the \(5n\) gates of the ripple-carry adder, followed by an XOR of the carry into bit \(n - 1\) and the carry into bit \(n\) (the carry out). Here the carry into bit \(0\) is the carry in, and for \(n = 0\) the index \(n - 1\) is read as \(0\). Its \(n + 2\) outputs are the ripple-carry adder's \(n\) sum bits and carry out, followed by the new gate, the signed-overflow flag.
def overflowAdder (n : ℕ) : Circuit arithSignature (2 * n + 1) (n + 2) where
size := 5 * n + 1
program := (rcaProgram n (5 * n) (Nat.le_refl _)).gate
(binLine .xor (carryWire n (5 * n) (n - 1) (by omega)) (carryWire n (5 * n) n (Nat.le_refl _)))
outputs o :=
if h : o.val < n + 1 then Wire.castSucc ((rippleCarryAdder n).outputs ⟨o.val, h⟩)
else Wire.gate (Fin.last (5 * n))
def arithSignature : Signature where
Op := ArithGate
Arity _ := 2
CSLibExt/Computability/Circuit/Arithmetic/RippleCarry.lean:58
def rcaProgram (n : ℕ) : (g : ℕ) → g ≤ 5 * n → Program arithSignature (2 * n + 1) g
| 0, _ => .empty
| g + 1, h => (rcaProgram n g (by omega)).gate (line n g (by omega))
CSLibExt/Computability/Circuit/Arithmetic/RippleCarry.lean:115
def binLine {m g : ℕ} (op : ArithGate) (u v : Wire m g) : Line arithSignature m g :=
⟨op, fun k => if k.val = 0 then u else v⟩
CSLibExt/Computability/Circuit/Arithmetic/RippleCarry.lean:78
def carryWire (n g i : ℕ) (hi : 5 * i ≤ g) : Wire (2 * n + 1) g :=
if h : i = 0 then Wire.input ⟨2 * n, by omega⟩ else Wire.gate ⟨5 * i - 1, by omega⟩
CSLibExt/Computability/Circuit/Arithmetic/RippleCarry.lean:96
Uses 6 · Used by 4
TheoremThe overflow adder extends the ripple-carry adder#✓fully proved
Let \(x\) and \(y\) be \(n\)-bit words and let \(c\) be a carry-in bit. Evaluate the \(n\)-bit overflow adder and the \(n\)-bit ripple-carry adder, with XOR, AND and OR gates, on the bits of \(x\), the bits of \(y\) and \(c\). Then for every \(o < n + 1\), output \(o\) of the overflow adder equals output \(o\) of the ripple-carry adder: the first \(n + 1\) outputs (the \(n\) sum bits and the carry out) agree.
theorem overflowAdder_eval_of_lt (c : Bool) (o : ℕ) (ho : o < n + 1) :
(overflowAdder n).eval arithInterpretation (rcaInput x y c) ⟨o, by omega⟩ =
(rippleCarryAdder n).eval arithInterpretation (rcaInput x y c) ⟨o, ho⟩
def overflowAdder (n : ℕ) : Circuit arithSignature (2 * n + 1) (n + 2) where
size := 5 * n + 1
program := (rcaProgram n (5 * n) (Nat.le_refl _)).gate
(binLine .xor (carryWire n (5 * n) (n - 1) (by omega)) (carryWire n (5 * n) n (Nat.le_refl _)))
outputs o :=
if h : o.val < n + 1 then Wire.castSucc ((rippleCarryAdder n).outputs ⟨o.val, h⟩)
else Wire.gate (Fin.last (5 * n))
CSLibExt/Computability/Circuit/Arithmetic/TwosComplement.lean:105
def arithInterpretation : Interpretation arithSignature Bool
| .xor, f => f ⟨0, by decide⟩ ^^ f ⟨1, by decide⟩
| .and, f => f ⟨0, by decide⟩ && f ⟨1, by decide⟩
| .or, f => f ⟨0, by decide⟩ || f ⟨1, by decide⟩
CSLibExt/Computability/Circuit/Arithmetic/RippleCarry.lean:63
def rcaInput {n : ℕ} (x y : BitVec n) (c : Bool) : Fin (2 * n + 1) → Bool := fun j =>
if j.val < n then x.getLsbD j.val else if j.val < 2 * n then y.getLsbD (j.val - n) else c
CSLibExt/Computability/Circuit/Arithmetic/RippleCarry.lean:128
Uses 9 · Used by 1
TheoremThe overflow flag#✓fully proved
Let \(n \ge 1\) and let \(x\) and \(y\) be \(n\)-bit words. Evaluate the \(n\)-bit overflow adder, with XOR, AND and OR gates, on the bits of \(x\), the bits of \(y\) and carry in \(0\). Its last output (output \(n + 1\)) is \(1\) exactly when the two's complement addition \(x + y\) overflows, that is, when the sum of the two's complement values of \(x\) and \(y\) is at least \(2^{n-1}\) or less than \(-2^{n-1}\).
theorem overflowAdder_overflow (hn : 0 < n) :
(overflowAdder n).eval arithInterpretation (rcaInput x y false) ⟨n + 1, by omega⟩ =
x.saddOverflow y
def overflowAdder (n : ℕ) : Circuit arithSignature (2 * n + 1) (n + 2) where
size := 5 * n + 1
program := (rcaProgram n (5 * n) (Nat.le_refl _)).gate
(binLine .xor (carryWire n (5 * n) (n - 1) (by omega)) (carryWire n (5 * n) n (Nat.le_refl _)))
outputs o :=
if h : o.val < n + 1 then Wire.castSucc ((rippleCarryAdder n).outputs ⟨o.val, h⟩)
else Wire.gate (Fin.last (5 * n))
CSLibExt/Computability/Circuit/Arithmetic/TwosComplement.lean:105
def arithInterpretation : Interpretation arithSignature Bool
| .xor, f => f ⟨0, by decide⟩ ^^ f ⟨1, by decide⟩
| .and, f => f ⟨0, by decide⟩ && f ⟨1, by decide⟩
| .or, f => f ⟨0, by decide⟩ || f ⟨1, by decide⟩
CSLibExt/Computability/Circuit/Arithmetic/RippleCarry.lean:63
def rcaInput {n : ℕ} (x y : BitVec n) (c : Bool) : Fin (2 * n + 1) → Bool := fun j =>
if j.val < n then x.getLsbD j.val else if j.val < 2 * n then y.getLsbD (j.val - n) else c
CSLibExt/Computability/Circuit/Arithmetic/RippleCarry.lean:128
Uses 13
TheoremSum bits of the overflow adder#✓fully proved
Let \(x\) and \(y\) be \(n\)-bit words. Evaluate the \(n\)-bit overflow adder, with XOR, AND and OR gates, on the bits of \(x\), the bits of \(y\) and carry in \(0\). Then for every \(i < n\), output \(i\) is bit \(i\) (counting from the least significant bit \(0\)) of \(x + y\) modulo \(2^n\).
theorem overflowAdder_sum (i : ℕ) (hi : i < n) :
(overflowAdder n).eval arithInterpretation (rcaInput x y false) ⟨i, by omega⟩ =
(x + y).getLsbD i
def overflowAdder (n : ℕ) : Circuit arithSignature (2 * n + 1) (n + 2) where
size := 5 * n + 1
program := (rcaProgram n (5 * n) (Nat.le_refl _)).gate
(binLine .xor (carryWire n (5 * n) (n - 1) (by omega)) (carryWire n (5 * n) n (Nat.le_refl _)))
outputs o :=
if h : o.val < n + 1 then Wire.castSucc ((rippleCarryAdder n).outputs ⟨o.val, h⟩)
else Wire.gate (Fin.last (5 * n))
CSLibExt/Computability/Circuit/Arithmetic/TwosComplement.lean:105
def arithInterpretation : Interpretation arithSignature Bool
| .xor, f => f ⟨0, by decide⟩ ^^ f ⟨1, by decide⟩
| .and, f => f ⟨0, by decide⟩ && f ⟨1, by decide⟩
| .or, f => f ⟨0, by decide⟩ || f ⟨1, by decide⟩
CSLibExt/Computability/Circuit/Arithmetic/RippleCarry.lean:63
def rcaInput {n : ℕ} (x y : BitVec n) (c : Bool) : Fin (2 * n + 1) → Bool := fun j =>
if j.val < n then x.getLsbD j.val else if j.val < 2 * n then y.getLsbD (j.val - n) else c
CSLibExt/Computability/Circuit/Arithmetic/RippleCarry.lean:128
TheoremSize of the overflow adder#✓fully proved
The \(n\)-bit overflow adder has \(5n + 1\) gates.
This is one gate more than the \(5n\) gates of the \(n\)-bit ripple-carry adder.
theorem overflowAdder_size : (overflowAdder n).size = 5 * n + 1
def overflowAdder (n : ℕ) : Circuit arithSignature (2 * n + 1) (n + 2) where
size := 5 * n + 1
program := (rcaProgram n (5 * n) (Nat.le_refl _)).gate
(binLine .xor (carryWire n (5 * n) (n - 1) (by omega)) (carryWire n (5 * n) n (Nat.le_refl _)))
outputs o :=
if h : o.val < n + 1 then Wire.castSucc ((rippleCarryAdder n).outputs ⟨o.val, h⟩)
else Wire.gate (Fin.last (5 * n))
CSLibExt/Computability/Circuit/Arithmetic/TwosComplement.lean:105
Uses 2
Loading dependency explorer…
The dependency explorer needs JavaScript and its graph data.