Documentation

Mathlib.Data.Nat.Log

Natural number logarithms #

This file defines two -valued analogs of the logarithm of n with base b:

These are interesting because, for 1 < b, Nat.log b and Nat.clog b are respectively right and left adjoints of (b ^ ·). See le_log_iff_pow_le and clog_le_iff_le_pow.

Implementation notes #

We define both functions using recursion on b. In order to compute, e.g., Nat.log b n, we compute e = Nat.log (b * b) n first, then figure out whether the answer is 2 * e or 2 * e + 1. The actual implementations use fuel recursion so that (by decide : Nat.log 2 20 = 4) works.

Adapted from https://downloads.haskell.org/~ghc/9.0.1/docs/html/libraries/ghc-bignum-1.0/GHC-Num-BigNat.html#v:bigNatLogBase-35-

Note a tail-recursive version of Nat.log is also possible:

def logTR (b n : ℕ) : ℕ :=
  let rec go : ℕ → ℕ → ℕ | n, acc => if h : b ≤ n ∧ 1 < b then go (n / b) (acc + 1) else acc
  decreasing_by
    have : n / b < n := Nat.div_lt_self (by omega) h.2
    decreasing_trivial
  go n 0

but performs worse for large numbers than Nat.log:

#eval Nat.logTR 2 (2 ^ 1000000)
#eval Nat.log 2 (2 ^ 1000000)

Floor logarithm #

def Nat.log (b n : ) :

log b n, is the logarithm of natural number n in base b. It returns the largest k : ℕ such that b^k ≤ n, so if b^k = n, it returns exactly k.

Equations
Instances For
    def Nat.log.go (n : ) :
    ×

    An auxiliary definition for Nat.log.

    For b > 1, n ≠ 0, n < b ^ fuel, Nat.log.go n b fuel = (n / b ^ b.log n, b.log n).

    Equations
    Instances For
      theorem Nat.log_of_left_le_one {b : } (hb : b 1) (n : ) :
      log b n = 0
      theorem Nat.log_of_lt {b n : } (hb : n < b) :
      log b n = 0
      theorem Nat.log.go_spec {b n fuel : } (hb : 1 < b) (hn : n 0) (hfuel : n < b ^ fuel) :
      (go n b fuel).fst = n / b ^ (go n b fuel).snd b ^ (go n b fuel).snd n n < b ^ ((go n b fuel).snd + 1)
      theorem Nat.log_lt_iff_lt_pow {b : } (hb : 1 < b) {x y : } (hy : y 0) :
      log b y < x y < b ^ x
      @[simp]
      theorem Nat.log_eq_zero_iff {b n : } :
      log b n = 0 n < b b 1
      @[simp]
      theorem Nat.log_pos_iff {b n : } :
      0 < log b n b n 1 < b
      theorem Nat.log_pos {b n : } (hb : 1 < b) (hbn : b n) :
      0 < log b n
      theorem Nat.log_of_one_lt_of_le {b n : } (h : 1 < b) (hn : b n) :
      log b n = log b (n / b) + 1
      @[simp]
      theorem Nat.log_zero_left (n : ) :
      log 0 n = 0
      @[simp]
      theorem Nat.log_zero_right (b : ) :
      log b 0 = 0
      @[simp]
      theorem Nat.log_one_left (n : ) :
      log 1 n = 0
      @[simp]
      theorem Nat.log_one_right (b : ) :
      log b 1 = 0
      theorem Nat.le_log_iff_pow_le {b : } (hb : 1 < b) {x y : } (hy : y 0) :
      x log b y b ^ x y

      (b ^ ·) and log b (almost) form a Galois connection. See also Nat.pow_le_of_le_log and Nat.le_log_of_pow_le for individual implications under weaker assumptions.

      @[deprecated Nat.le_log_iff_pow_le (since := "2025-10-05")]
      theorem Nat.pow_le_iff_le_log {b : } (hb : 1 < b) {x y : } (hy : y 0) :
      b ^ x y x log b y
      @[deprecated Nat.log_lt_iff_lt_pow (since := "2025-10-05")]
      theorem Nat.lt_pow_iff_log_lt {b : } (hb : 1 < b) {x y : } (hy : y 0) :
      y < b ^ x log b y < x
      theorem Nat.pow_le_of_le_log {b x y : } (hy : y 0) (h : x log b y) :
      b ^ x y
      theorem Nat.le_log_of_pow_le {b x y : } (hb : 1 < b) (h : b ^ x y) :
      x log b y
      theorem Nat.pow_log_le_self (b : ) {x : } (hx : x 0) :
      b ^ log b x x
      theorem Nat.log_lt_of_lt_pow {b x y : } (hy : y 0) :
      y < b ^ xlog b y < x

      See also log_lt_of_lt_pow' for a version that assumes x ≠ 0 instead of y ≠ 0.

      theorem Nat.log_lt_of_lt_pow' {b x y : } (hx : x 0) (hlt : y < b ^ x) :
      log b y < x

      A version of log_lt_of_lt_pow that assumes x ≠ 0 instead of y ≠ 0.

      theorem Nat.lt_pow_of_log_lt {b x y : } (hb : 1 < b) :
      log b y < xy < b ^ x
      theorem Nat.log_lt_self (b : ) {x : } (hx : x 0) :
      log b x < x
      theorem Nat.log_le_self (b x : ) :
      log b x x
      theorem Nat.lt_pow_succ_log_self {b : } (hb : 1 < b) (x : ) :
      x < b ^ (log b x).succ
      theorem Nat.log_eq_iff {b m n : } (h : m 0 1 < b n 0) :
      log b n = m b ^ m n n < b ^ (m + 1)
      theorem Nat.log_eq_of_pow_le_of_lt_pow {b m n : } (h₁ : b ^ m n) (h₂ : n < b ^ (m + 1)) :
      log b n = m
      @[simp]
      theorem Nat.log_pow {b : } (hb : 1 < b) (x : ) :
      log b (b ^ x) = x
      theorem Nat.log_eq_one_iff' {b n : } :
      log b n = 1 b n n < b * b
      theorem Nat.log_eq_one_iff {b n : } :
      log b n = 1 n < b * b 1 < b b n
      @[simp]
      theorem Nat.log_mul_base {b n : } (hb : 1 < b) (hn : n 0) :
      log b (n * b) = log b n + 1
      theorem Nat.pow_log_le_add_one (b x : ) :
      b ^ log b x x + 1
      theorem Nat.log_mono_right {b n m : } (h : n m) :
      log b n log b m
      theorem Nat.log_lt_log_succ_iff {b n : } (hb : 1 < b) (hn : n 0) :
      log b n < log b (n + 1) b ^ log b (n + 1) = n + 1
      theorem Nat.log_eq_log_succ_iff {b n : } (hb : 1 < b) (hn : n 0) :
      log b n = log b (n + 1) b ^ log b (n + 1) n + 1
      theorem Nat.log_anti_left {b c n : } (hc : 1 < c) (hb : c b) :
      log b n log c n
      theorem Nat.log_antitone_left {n : } :
      AntitoneOn (fun (b : ) => log b n) (Set.Ioi 1)
      theorem Nat.log_mono {b c m n : } (hc : 1 < c) (hb : c b) (hmn : m n) :
      log b m log c n
      @[simp]
      theorem Nat.log_div_base (b n : ) :
      log b (n / b) = log b n - 1
      theorem Nat.log_div_base_pow (b n k : ) :
      log b (n / b ^ k) = log b n - k
      @[simp]
      theorem Nat.log_div_mul_self (b n : ) :
      log b (n / b * b) = log b n
      theorem Nat.add_pred_div_lt {b n : } (hb : 1 < b) (hn : 2 n) :
      (n + b - 1) / b < n
      theorem Nat.log_two_bit {b : Bool} {n : } (hn : n 0) :
      log 2 (bit b n) = log 2 n + 1
      theorem Nat.log2_eq_log_two {n : } :
      n.log2 = log 2 n
      @[simp]
      theorem Nat.log_pow_left (b k n : ) :
      log (b ^ k) n = log b n / k

      Ceil logarithm #

      def Nat.clog (b n : ) :

      clog b n, is the upper logarithm of natural number n in base b. It returns the smallest k : ℕ such that n ≤ b^k, so if b^k = n, it returns exactly k.

      Equations
      Instances For
        def Nat.clog.go (n : ) :
        ×

        An auxiliary definition for Nat.clog.

        For n > 1, b > 1, n ≤ b ^ fuel, returns (b ^ clog b n / n, clog b n - 1).

        Equations
        Instances For
          theorem Nat.clog_of_left_le_one {b : } (hb : b 1) (n : ) :
          clog b n = 0
          theorem Nat.clog_of_right_le_one {n : } (hn : n 1) (b : ) :
          clog b n = 0
          @[simp]
          theorem Nat.clog_zero_left (n : ) :
          clog 0 n = 0
          @[simp]
          theorem Nat.clog_zero_right (b : ) :
          clog b 0 = 0
          @[simp]
          theorem Nat.clog_one_left (n : ) :
          clog 1 n = 0
          @[simp]
          theorem Nat.clog_one_right (b : ) :
          clog b 1 = 0
          theorem Nat.clog.go_spec {n b fuel : } (hn : 1 < n) (hb : 1 < b) (hfuel : n < b ^ fuel) :
          (go n b fuel).fst = b ^ ((go n b fuel).snd + 1) / n b ^ (go n b fuel).snd < n n b ^ ((go n b fuel).snd + 1)
          theorem Nat.clog_le_iff_le_pow {b : } (hb : 1 < b) {x y : } :
          clog b x y x b ^ y

          For b > 1, clog b and (b ^ ·) form a Galois connection.

          See also clog_le_of_le_pow for the implication that does not require 1 < b.

          theorem Nat.clog_pos {b n : } (hb : 1 < b) (hn : 1 < n) :
          0 < clog b n
          theorem Nat.clog_of_one_lt {b n : } (hb : 1 < b) (hn : 1 < n) :
          clog b n = clog b ((n + b - 1) / b) + 1
          theorem Nat.clog_of_two_le {b n : } (hb : 1 < b) (hn : 2 n) :
          clog b n = clog b ((n + b - 1) / b) + 1
          theorem Nat.clog_eq_one {b n : } (hn : 2 n) (h : n b) :
          clog b n = 1
          theorem Nat.clog_le_of_le_pow {b x y : } (h : x b ^ y) :
          clog b x y
          @[deprecated Nat.clog_le_iff_le_pow (since := "2025-10-05")]
          theorem Nat.le_pow_iff_clog_le {b : } (hb : 1 < b) {x y : } :
          x b ^ y clog b x y
          theorem Nat.lt_clog_iff_pow_lt {b : } (hb : 1 < b) {x y : } :
          y < clog b x b ^ y < x
          @[deprecated Nat.lt_clog_iff_pow_lt (since := "2025-10-05")]
          theorem Nat.pow_lt_iff_lt_clog {b : } (hb : 1 < b) {x y : } :
          b ^ y < x y < clog b x
          theorem Nat.pow_lt_of_lt_clog {b x y : } (h : y < clog b x) :
          b ^ y < x
          @[simp]
          theorem Nat.clog_pow (b x : ) (hb : 1 < b) :
          clog b (b ^ x) = x
          theorem Nat.pow_pred_clog_lt_self {b : } (hb : 1 < b) {x : } (hx : 1 < x) :
          b ^ (clog b x).pred < x
          theorem Nat.le_pow_clog {b : } (hb : 1 < b) (x : ) :
          x b ^ clog b x
          theorem Nat.clog_mono_right (b : ) {n m : } (h : n m) :
          clog b n clog b m
          theorem Nat.clog_anti_left {b c n : } (hc : 1 < c) (hb : c b) :
          clog b n clog c n
          theorem Nat.clog_antitone_left {n : } :
          AntitoneOn (fun (b : ) => clog b n) (Set.Ioi 1)
          theorem Nat.clog_mono {b c m n : } (hc : 1 < c) (hb : c b) (hmn : m n) :
          clog b m clog c n
          @[simp]
          theorem Nat.log_le_clog (b n : ) :
          log b n clog b n
          theorem Nat.clog_lt_clog_succ_iff {b n : } (hb : 1 < b) :
          clog b n < clog b (n + 1) b ^ clog b n = n
          theorem Nat.clog_eq_clog_succ_iff {b n : } (hb : 1 < b) :
          clog b n = clog b (n + 1) b ^ clog b n n
          theorem Nat.clog_pow_left (b k n : ) :
          clog (b ^ k) n = (clog b n + (k - 1)) / k

          This lemma says that `⌈log (b ^ k) n⌉ = ⌈(⌈log b n⌉ / k)⌉, using operations on natural numbers to express this equality.

          Since Lean has no dedicated function for the ceiling division, we use (a + (b - 1)) / b for ⌈a / b⌉.