Module docstring
{"### testBit We define an operation for testing individual bits in the binary representation of a number. "}
{"### testBit We define an operation for testing individual bits in the binary representation of a number. "}
Nat.bitwise_rec_lemma
theorem
{n : Nat} (hNe : n ≠ 0) : n / 2 < n
theorem bitwise_rec_lemma {n : Nat} (hNe : n ≠ 0) : n / 2 < n :=
Nat.div_lt_self (Nat.zero_lt_of_ne_zero hNe) (Nat.lt_succ_self _)
Nat.bitwise
definition
(f : Bool → Bool → Bool) (n m : Nat) : Nat
/--
A helper for implementing bitwise operators on `Nat`.
Each bit of the resulting `Nat` is the result of applying `f` to the corresponding bits of the input
`Nat`s, up to the position of the highest set bit in either input.
-/
def bitwise (f : Bool → Bool → Bool) (n m : Nat) : Nat :=
if n = 0 then
if f false true then m else 0
else if m = 0 then
if f true false then n else 0
else
let n' := n / 2
let m' := m / 2
let b₁ := n % 2 = 1
let b₂ := m % 2 = 1
let r := bitwise f n' m'
if f b₁ b₂ then
r+r+1
else
r+r
decreasing_by apply bitwise_rec_lemma; assumption
Nat.land
definition
: @& Nat → @& Nat → Nat
Nat.lor
definition
: @& Nat → @& Nat → Nat
Nat.xor
definition
: @& Nat → @& Nat → Nat
Nat.shiftLeft
definition
: @& Nat → @& Nat → Nat
/--
Shifts the binary representation of a value left by the specified number of bits. Usually accessed
via the `<<<` operator.
Examples:
* `1 <<< 2 = 4`
* `1 <<< 3 = 8`
* `0 <<< 3 = 0`
* `0xf1 <<< 4 = 0xf10`
-/
@[extern "lean_nat_shiftl"]
def shiftLeft : @& Nat → @& Nat → Nat
| n, 0 => n
| n, succ m => shiftLeft (2*n) m
Nat.shiftRight
definition
: @& Nat → @& Nat → Nat
/--
Shifts the binary representation of a value right by the specified number of bits. Usually accessed
via the `>>>` operator.
Examples:
* `4 >>> 2 = 1`
* `8 >>> 2 = 2`
* `8 >>> 3 = 1`
* `0 >>> 3 = 0`
* `0xf13a >>> 8 = 0xf1`
-/
@[extern "lean_nat_shiftr"]
def shiftRight : @& Nat → @& Nat → Nat
| n, 0 => n
| n, succ m => shiftRight n m / 2
Nat.instAndOp
instance
: AndOp Nat
instance : AndOp Nat := ⟨Nat.land⟩
Nat.instOrOp
instance
: OrOp Nat
Nat.instXor
instance
: Xor Nat
Nat.instShiftLeft
instance
: ShiftLeft Nat
instance : ShiftLeft Nat := ⟨Nat.shiftLeft⟩
Nat.instShiftRight
instance
: ShiftRight Nat
instance : ShiftRight Nat := ⟨Nat.shiftRight⟩
Nat.shiftLeft_eq
theorem
(a b : Nat) : a <<< b = a * 2 ^ b
theorem shiftLeft_eq (a b : Nat) : a <<< b = a * 2 ^ b :=
match b with
| 0 => (Nat.mul_one _).symm
| b+1 => (shiftLeft_eq _ b).trans <| by
simp [Nat.pow_succ, Nat.mul_assoc, Nat.mul_left_comm, Nat.mul_comm]
Nat.shiftRight_zero
theorem
: n >>> 0 = n
@[simp] theorem shiftRight_zero : n >>> 0 = n := rfl
Nat.shiftRight_succ
theorem
(m n) : m >>> (n + 1) = (m >>> n) / 2
theorem shiftRight_succ (m n) : m >>> (n + 1) = (m >>> n) / 2 := rfl
Nat.shiftRight_add
theorem
(m n : Nat) : ∀ k, m >>> (n + k) = (m >>> n) >>> k
theorem shiftRight_add (m n : Nat) : ∀ k, m >>> (n + k) = (m >>> n) >>> k
| 0 => rfl
| k + 1 => by simp [← Nat.add_assoc, shiftRight_add _ _ k, shiftRight_succ]
Nat.shiftRight_eq_div_pow
theorem
(m : Nat) : ∀ n, m >>> n = m / 2 ^ n
theorem shiftRight_eq_div_pow (m : Nat) : ∀ n, m >>> n = m / 2 ^ n
| 0 => (Nat.div_one _).symm
| k + 1 => by
rw [shiftRight_add, shiftRight_eq_div_pow m k]
simp [Nat.div_div_eq_div_mul, ← Nat.pow_succ, shiftRight_succ]
Nat.shiftRight_eq_zero
theorem
(m n : Nat) (hn : m < 2 ^ n) : m >>> n = 0
theorem shiftRight_eq_zero (m n : Nat) (hn : m < 2^n) : m >>> n = 0 := by
simp [Nat.shiftRight_eq_div_pow, Nat.div_eq_of_lt hn]
Nat.shiftRight_le
theorem
(m n : Nat) : m >>> n ≤ m
theorem shiftRight_le (m n : Nat) : m >>> n ≤ m := by
simp only [shiftRight_eq_div_pow]
apply Nat.div_le_self
Nat.testBit
definition
(m n : Nat) : Bool
/--
Returns `true` if the `(n+1)`th least significant bit is `1`, or `false` if it is `0`.
-/
def testBit (m n : Nat) : Bool :=
-- `1 &&& n` is faster than `n &&& 1` for big `n`.
1 &&& (m >>> n) != 0