@@ -431,32 +431,34 @@ theorem shiftLeft_eq_shiftLeftRec (x : BitVec w₁) (y : BitVec w₂) :
431
431
432
432
/-! # udiv/urem recurrence for bitblasting
433
433
434
- Let us study an instructive counterexample to the claim that
435
- `n = d * q + r` for (`0 ≤ r < d`) uniquely determining q and r *over bitvectors* .
434
+ In order to prove the correctness of the division algorithm on the integers,
435
+ one shows that `n.div d = q` and `n.mod d = r` iff `n = d * q + r` and `0 ≤ r < d`.
436
+ Mnemonic: `n` is the numerator, `d` is the denominator, `q` is the quotient, and `r` the remainder.
437
+
438
+ This uniqueness property is not true for bitvectors.
439
+ Let us study an instructive counterexample:
436
440
437
441
- Let `bitwidth = 3`
438
442
- Let `n = 0, d = 3`
439
- - If we choose `q = 2, r = 2`, then d * q + r = 6 + 2 = 8 ≃ 0 (mod 8) so satisfies.
440
- - But see that `q = 0, r = 0` also satisfies, as 0 * 3 + 0 = 0.
441
- - So for (`n = 0, d = 3`), both:
442
- `q = 2, r = 2` as well as
443
- `q = 0, r = 0` are solutions!
443
+ - If we choose `q = 2, r = 2`, then `d * q + r = 6 + 2 = 8 ≃ 0 (mod 8)` and (`r < d`).
444
+ - But see that `q = 0, r = 0` also satisfies the constraints, as `0 * 3 + 0 = 0`.
445
+ - So for (`n = 0, d = 3`), both (a) `q = 2, r = 2` as well as (b) `q = 0, r = 0` are solutions!
444
446
445
- It's easy to cook up such examples, by chosing `(q, r)` for a fixed `(d, n)`
446
- such that `(d * q + r)` overflows.
447
+ Such examples can be created by choosing `(q, r)` for a fixed `(d, n)`
448
+ such that `(d * q + r)` overflows and wraps around to equal `n` .
447
449
448
450
This tells us that the division algorithm must have more restrictions that just the ones
449
451
we have for natural numbers. These restrictions are captured in `DivModState.Lawful`,
450
452
which captures the relationship necessary between `n, d, q, r`. The key idea is to state
451
- the relationship in terms of the `{n, d, q, r}.toNat` values, and then prove that the relationship
452
- holds for the bitvector values .
453
+ the relationship in terms of the `{n, d, q, r}.toNat` values, which implies that the
454
+ relationship also holds at the bitvector level .
453
455
454
456
References:
455
457
- Fast 32-bit Division on the DSP56800E: Minimized nonrestoring division algorithm by David Baca
456
458
- Bitwuzla sources for bitblasting.h
457
459
-/
458
460
459
- private theorem Nat.div_add_eq_left_of_lt {x y z : Nat} (hx : z ∣ x) (hy : y < z) (hz : 0 < z):
461
+ private theorem Nat.div_add_eq_left_of_lt {x y z : Nat} (hx : z ∣ x) (hy : y < z) (hz : 0 < z) :
460
462
(x + y) / z = x / z := by
461
463
refine Nat.div_eq_of_lt_le ?lo ?hi
462
464
· apply Nat.le_trans
@@ -519,9 +521,6 @@ This is a proof engineering choice: An alternative world could have
519
521
520
522
Instead, we choose to declare all involved bitvectors as length `w`, and then prove that
521
523
the values of `r` and `n` are within the bounds of `wr` and `wn` respectively.
522
-
523
- Note that `DivModState` manipulates thw widths of the remainder and the dividend,
524
-
525
524
-/
526
525
structure DivModState.Lawful (w wr wn : Nat) (n d : BitVec w)
527
526
(qr : DivModState w) : Prop where
@@ -554,7 +553,7 @@ def DivModState.init (w : Nat) : DivModState w := {
554
553
r := 0 #w
555
554
}
556
555
557
- /-- Make an initial state of the DivModState, for a given choice of `n, d, q, r` . -/
556
+ /-- The initial state. -/
558
557
def DivModState.Lawful.init (w : Nat) (n d : BitVec w) (hd : 0 #w < d) :
559
558
DivModState.Lawful w 0 w n d (DivModState.init w) := {
560
559
hwrn := by omega,
@@ -593,6 +592,12 @@ theorem DivModState.umod_eq_of_lawful_zero {qr : DivModState w}
593
592
594
593
/-! ### LawfulShiftSubtract -/
595
594
595
+ /-!
596
+ A `LawfulShiftSubtract` is a `Lawful` DivModState that is also a legal input to the shift subtractor.
597
+ So in particular, we must have at least one dividend bit left over `(0 < wn)`
598
+ to perform a round of shift subtraction.
599
+ -/
600
+
596
601
/--
597
602
The input to the shift subtractor is a legal input to `divrem`, and we also need to have an
598
603
input bit to perform shift subtraction on, and thus we need `0 < wn`.
0 commit comments