Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

The Bohr–Mollerup theorem

The gamma function is defined for x>0x>0 by Euler’s integral

Γ(x)=0tx1etdt.\Gamma(x)=\int_0^\infty t^{x-1}e^{-t}\,\mathrm{d}t .

It extends the factorial, Γ(n)=(n1)!\Gamma(n)=(n-1)!, and satisfies Γ(x+1)=xΓ(x)\Gamma(x+1)=x\,\Gamma(x). But infinitely many functions interpolate the factorial. The Bohr–Mollerup theorem Bohr & Mollerup, 1922, given the elegant treatment reproduced here by Artin Artin, 1964, singles out Γ\Gamma by one extra qualitative condition: logarithmic convexity.

Theorem (Bohr–Mollerup). The gamma function is the unique function f ⁣:(0,)(0,)f\colon(0,\infty)\to(0,\infty) that simultaneously satisfies

  1. f(1)=1f(1)=1;

  2. f(x+1)=xf(x)f(x+1)=x\,f(x) for all x>0x>0;

  3. logf\log f is convex on (0,)(0,\infty).

Here “log-convex” means that logf\log\circ f is a convex function; equivalently f(λa+(1λ)b)f(a)λf(b)1λf\big(\lambda a+(1-\lambda)b\big)\le f(a)^{\lambda}f(b)^{1-\lambda} for λ[0,1]\lambda\in[0,1].

Lean: the three properties GammaLike and the theorem bohr_mollerup
BohrMollerupFlow.lean
/-- The three Bohr–Mollerup hypotheses on a function `f : ℝ → ℝ`, packaged as a predicate:
`f` is positive and log-convex on `(0, ∞)`, satisfies `f (x + 1) = x · f x`, and `f 1 = 1`.
The theorem below says `Real.Gamma` is the unique such function. -/
structure GammaLike (f : ℝ → ℝ) : Prop where
  /-- `f` is positive on the positive reals. -/
  pos : ∀ x, 0 < x → 0 < f x
  /-- The Gamma functional equation `f (x + 1) = x · f x`. -/
  functional_eq : ∀ x, 0 < x → f (x + 1) = x * f x
  /-- `log ∘ f` is convex on the positive reals (i.e. `f` is log-convex). -/
  log_convex : ConvexOn ℝ (Ioi 0) (Real.log ∘ f)
  /-- Normalization `f 1 = 1`. -/
  one : f 1 = 1
BohrMollerupFlow.lean
/-- **The Bohr–Mollerup theorem.** `Real.Gamma` is `GammaLike`, and it is the *unique* `GammaLike`
function: every function that is positive and log-convex on `(0, ∞)`, satisfies
`f (x + 1) = x · f x`, and has `f 1 = 1`, coincides with `Real.Gamma` on `(0, ∞)`. -/
theorem bohr_mollerup :
    GammaLike Real.Gamma ∧ ∀ f, GammaLike f → EqOn f Real.Gamma (Ioi 0) :=
  ⟨gammaLike_Gamma, fun _ hf => hf.eq_Gamma⟩

The proof has two halves: uniqueness (any ff with properties 1–3 is forced to equal a specific limit, hence equals Γ\Gamma) and existence (Γ\Gamma itself has all three properties). The heart of the argument is uniqueness.

Step 1: the functional equation reproduces the factorials

Assume ff satisfies properties 1–3. Property 2 applied repeatedly, with f(1)=1f(1)=1, gives by induction

f(n+1)=n!(nN),f(n+1)=n! \qquad (n\in\mathbb{N}),

so ff interpolates the factorials just like Γ\Gamma. More generally, iterating f(x+1)=xf(x)f(x+1)=x\,f(x) exactly nn times yields the product formula

f(x+n)=f(x)m=0n1(x+m)=x(x+1)(x+n1)f(x).f(x+n)=f(x)\,\prod_{m=0}^{n-1}(x+m)=x(x+1)\cdots(x+n-1)\,f(x).

The consequence is decisive: (3) lets us recover f(x)f(x) for any x>0x>0 from its values on the unit interval (0,1](0,1]. So it suffices to pin down ff on (0,1](0,1].

Lean proof: GammaLike.f_nat (factorials) and GammaLike.f_add_nat (product formula)
BohrMollerupFlow.lean
/-- **The functional equation forces the factorials.** From `f (x + 1) = x · f x` and `f 1 = 1`,
induction gives `f (n + 1) = n !` for every natural number `n`; in particular `f` interpolates the
factorials, `f n = (n − 1)!`. -/
theorem GammaLike.f_nat (hf : GammaLike f) (n : ℕ) : f (n + 1) = n ! := by
  induction n with
  | zero => simpa using hf.one
  | succ k ih =>
    have hk : (0 : ℝ) < (k : ℝ) + 1 := by positivity
    have hrec := hf.functional_eq ((k : ℝ) + 1) hk
    rw [Nat.cast_succ, hrec, ih, Nat.factorial_succ]
    push_cast
    ring
BohrMollerupFlow.lean
/-- **The functional equation as a product.** Iterating `f (x + 1) = x · f x` `n` times gives
`f (x + n) = f x · x (x + 1) ⋯ (x + n − 1)`, i.e. `f (x + n) = f x · ∏_{m < n} (x + m)`. Knowing `f`
on `(0, 1]` therefore determines it everywhere on `(0, ∞)`. -/
theorem GammaLike.f_add_nat (hf : GammaLike f) (hx : 0 < x) (n : ℕ) :
    f (x + n) = f x * ∏ m ∈ Finset.range n, (x + m) := by
  induction n with
  | zero => simp
  | succ k ih =>
    have hxk : 0 < x + (k : ℝ) := by positivity
    have hrec := hf.functional_eq (x + (k : ℝ)) hxk
    have hcast : x + ((k : ℕ) + 1 : ℕ) = (x + (k : ℝ)) + 1 := by push_cast; ring
    rw [hcast, hrec, ih, Finset.prod_range_succ]
    ring

Step 2: log-convexity sandwiches the values

Fix xx with 0<x10<x\le 1 and write φ:=logf\varphi:=\log f, which is convex by property 3. For x1<x2x_1<x_2 let

S(x1,x2)=φ(x2)φ(x1)x2x1S(x_1,x_2)=\frac{\varphi(x_2)-\varphi(x_1)}{x_2-x_1}

be the slope of the secant of φ\varphi over [x1,x2][x_1,x_2]. Convexity is exactly the statement that SS is monotonically increasing in each argument. For an integer n2n\ge 2 consider the four points n1<n<n+xn+1n-1<n<n+x\le n+1. Monotonicity of the slopes gives

S(n1,n)    S(n,n+x)    S(n,n+1).S(n-1,\,n)\;\le\;S(n,\,n+x)\;\le\;S(n,\,n+1).

By (2), φ(n)=log((n1)!)\varphi(n)=\log\big((n-1)!\big) and φ(n+1)=log(n!)\varphi(n+1)=\log(n!), so the outer slopes collapse to logarithms of integers, S(n1,n)=log(n1)S(n-1,n)=\log(n-1) and S(n,n+1)=lognS(n,n+1)=\log n, while the middle slope is S(n,n+x)=(φ(n+x)φ(n))/xS(n,n+x)=\big(\varphi(n+x)-\varphi(n)\big)/x. Multiplying (5) by x>0x>0 and adding φ(n)\varphi(n) turns it into a sandwich of φ(n+x)\varphi(n+x) between two lines in xx:

log(f(n))+xlog(n1)    log(f(n+x))    log(f(n))+xlogn.\log\big(f(n)\big)+x\log(n-1)\;\le\;\log\big(f(n+x)\big)\;\le\;\log\big(f(n)\big)+x\log n .
Lean proof: GammaLike.log_sandwich (the two-line sandwich)
BohrMollerupFlow.lean
/-- **The log-convexity sandwich.** For `0 < x ≤ 1` and `n ≥ 2`, convexity of `log ∘ f` forces the
secant slopes of `log ∘ f` to be monotone, which traps `log (f (n + x))` between the two lines in
`x` through the lattice values of `log ∘ f`:
`log (f n) + x·log (n − 1) ≤ log (f (n + x)) ≤ log (f n) + x·log n`. -/
theorem GammaLike.log_sandwich (hf : GammaLike f) (hn : 2 ≤ n) (hx : 0 < x) (hx' : x ≤ 1) :
    Real.log (f n) + x * Real.log ((n : ℝ) - 1) ≤ Real.log (f (n + x)) ∧
      Real.log (f (n + x)) ≤ Real.log (f n) + x * Real.log n := by
  refine ⟨?_, ?_⟩
  · simpa [Function.comp_apply] using
      Real.BohrMollerup.f_add_nat_ge hf.log_convex hf.log_comp_feq hn hx
  · simpa [Function.comp_apply] using
      Real.BohrMollerup.f_add_nat_le hf.log_convex hf.log_comp_feq (by omega : n ≠ 0) hx hx'

Step 3: the Euler–Gauss limit

Now feed the product formula (3) into the sandwich (6). Taking logarithms of (3),

log(f(n+x))=log(f(x))+m=0n1log(x+m),\log\big(f(n+x)\big)=\log\big(f(x)\big)+\sum_{m=0}^{n-1}\log(x+m),

and, exponentiating (6) after substitution and solving for f(x)f(x), one obtains for every nn the two-sided bound

(n1)x(n1)!x(x+1)(x+n1)    f(x)    nxn!x(x+1)(x+n)n+xn.\frac{(n-1)^{x}\,(n-1)!}{x(x+1)\cdots(x+n-1)}\;\le\;f(x)\;\le\;\frac{n^{x}\,n!}{x(x+1)\cdots(x+n)}\cdot\frac{n+x}{n}.

Because (8) holds for every nn, the left- and right-hand sides may use different indices. Sending nn\to\infty and using n+xn1\frac{n+x}{n}\to 1 (equivalently log(n+1)logn0\log(n+1)-\log n\to 0), the two sides converge to a common value, squeezing f(x)f(x) to Gauss’s product limit

f(x)=limnnxn!x(x+1)(x+n).f(x)=\lim_{n\to\infty}\frac{n^{x}\,n!}{x(x+1)\cdots(x+n)} .

It is convenient to record this in logarithmic form. Setting

Ln(x):=xlogn+log(n!)m=0nlog(x+m)L_n(x):=x\log n+\log(n!)-\sum_{m=0}^{n}\log(x+m)

(so that eLn(x)e^{L_n(x)} is exactly the fraction in (9)), the squeeze says Ln(x)log(f(x))L_n(x)\to\log\big(f(x)\big).

Lean proof: GammaLike.logGammaSeq_tendsto (the squeeze) and GammaLike.gauss_product (the Gauss product limit)
BohrMollerupFlow.lean
/-- **The Euler/Gauss limit formula for `f`.** Exponentiating and letting `n → ∞` in the sandwich of
step 2 squeezes the Gauss sequence
`logGammaSeq x n = x·log n + log n! − ∑_{m ≤ n} log (x + m)` (the logarithm of
`nˣ · n! / (x (x+1) ⋯ (x+n))`) to `log (f x)`. Because the limit does not depend on `f`, this is the
uniqueness engine of the theorem. -/
theorem GammaLike.logGammaSeq_tendsto (hf : GammaLike f) (hx : 0 < x) :
    Tendsto (Real.BohrMollerup.logGammaSeq x) atTop (𝓝 (Real.log (f x))) := by
  have h := Real.BohrMollerup.tendsto_logGammaSeq hf.log_convex hf.log_comp_feq hx
  simpa only [Function.comp_apply, hf.one, Real.log_one, sub_zero] using h
BohrMollerupFlow.lean
/-- **The explicit Gauss product.** Unwinding step 3, the value of any admissible `f` is Gauss's
product limit `f x = limₙ nˣ · n! / (x (x+1) ⋯ (x+n))`. -/
theorem GammaLike.gauss_product (hf : GammaLike f) (hx : 0 < x) :
    Tendsto (fun n : ℕ => (n : ℝ) ^ x * (n ! : ℝ) / ∏ j ∈ Finset.range (n + 1), (x + j))
      atTop (𝓝 (f x)) := by
  have h := Real.GammaSeq_tendsto_Gamma x
  rw [← hf.eq_Gamma hx] at h
  exact h

Here logGammaSeq x n is Mathlib’s name for Ln(x)L_n(x), and the squeeze itself (monotone secant slopes plus log(n+1)logn0\log(n+1)-\log n\to 0) is provided by Mathlib’s Real.BohrMollerup.tendsto_logGammaSeq, which the Lean proof above specializes to our GammaLike hypotheses.

Step 4: uniqueness

The right-hand side of (9) makes no reference to ff: it is a fixed sequence built from xx and the integers. Hence its value is determined by xx alone. So if ff and gg both satisfy properties 1–3, then for every x>0x>0

f(x)=limnnxn!x(x+1)(x+n)=g(x),f(x)=\lim_{n\to\infty}\frac{n^{x}\,n!}{x(x+1)\cdots(x+n)}=g(x),

and the two functions coincide. In particular, since (as we check in Step 5) Γ\Gamma satisfies properties 1–3, and it too obeys Ln(x)logΓ(x)L_n(x)\to\log\Gamma(x), the uniqueness of limits forces logf(x)=logΓ(x)\log f(x)=\log\Gamma(x); as log\log is injective on (0,)(0,\infty) and both values are positive, f(x)=Γ(x)f(x)=\Gamma(x) for all x>0x>0.

Lean proof: GammaLike.eq_Gamma (every admissible function equals Γ) and GammaLike.unique (any two agree)
BohrMollerupFlow.lean
/-- **Uniqueness (each admissible `f` equals `Γ`).** Both `f` and `Real.Gamma` make `logGammaSeq x`
converge — to `log (f x)` and to `log (Γ x)` respectively — so those logs are equal by uniqueness of
limits, and injectivity of `log` on the positive reals gives `f x = Γ x` for all `x > 0`. -/
theorem GammaLike.eq_Gamma (hf : GammaLike f) : EqOn f Real.Gamma (Ioi 0) := by
  intro x hx
  have hx0 : 0 < x := hx
  have hlog : Real.log (f x) = Real.log (Real.Gamma x) :=
    tendsto_nhds_unique (hf.logGammaSeq_tendsto hx0) (Real.BohrMollerup.tendsto_log_gamma hx0)
  exact Real.log_injOn_pos (hf.pos x hx0) (Real.Gamma_pos_of_pos hx0) hlog
BohrMollerupFlow.lean
/-- Any two functions with the three Bohr–Mollerup properties agree on `(0, ∞)`. -/
theorem GammaLike.unique (hf : GammaLike f) (hg : GammaLike g) : EqOn f g (Ioi 0) :=
  fun _ hx => (hf.eq_Gamma hx).trans (hg.eq_Gamma hx).symm

Step 5: existence — Γ\Gamma qualifies

Uniqueness would be vacuous without a function that actually meets all three conditions. The gamma function (1) does:

  1. Normalization. Γ(1)=0etdt=1\Gamma(1)=\int_0^\infty e^{-t}\,\mathrm{d}t=1.

  2. Functional equation. Integration by parts gives Γ(x+1)=[txet]0+x0tx1etdt=xΓ(x)\Gamma(x+1)=\big[-t^{x}e^{-t}\big]_0^\infty+x\int_0^\infty t^{x-1}e^{-t}\,\mathrm{d}t=x\,\Gamma(x).

  3. Log-convexity. Applying Hölder’s inequality to Euler’s integral shows logΓ\log\Gamma is convex on (0,)(0,\infty).

Together with positivity of Γ\Gamma on (0,)(0,\infty), this establishes existence.

Lean proof: gammaLike_Gamma (Γ has all three properties)
BohrMollerupFlow.lean
/-- **Existence.** `Real.Gamma` satisfies the three properties: it is positive
(`Real.Gamma_pos_of_pos`), obeys `Γ (x + 1) = x · Γ x` (`Real.Gamma_add_one`), is log-convex
(`Real.convexOn_log_Gamma`), and is normalized `Γ 1 = 1` (`Real.Gamma_one`). -/
theorem gammaLike_Gamma : GammaLike Real.Gamma where
  pos := fun _ hx => Real.Gamma_pos_of_pos hx
  functional_eq := fun _ hx => Real.Gamma_add_one hx.ne'
  log_convex := Real.convexOn_log_Gamma
  one := Real.Gamma_one

Conclusion

Steps 1–4 show that at most one positive function on (0,)(0,\infty) can satisfy properties 1–3, and Step 5 shows Γ\Gamma is such a function. Therefore Γ\Gamma is the unique function with these properties — the Bohr–Mollerup theorem. The Lean statement bohr_mollerup in the first dropdown packages both halves: Γ\Gamma is GammaLike, and every GammaLike function equals Γ\Gamma on (0,)(0,\infty).

A pleasant by-product of the proof is the explicit Gauss product (9) for the gamma function, which fell out of the uniqueness argument without any extra work.

References

References
  1. Bohr, H., & Mollerup, J. (1922). Lærebog i matematisk Analyse: Vol. III. Jul. Gjellerup.
  2. Artin, E. (1964). The Gamma Function (M. Butler, Trans.). Holt, Rinehart.
  3. Wikipedia. (2025). Bohr–Mollerup theorem. https://en.wikipedia.org/wiki/Bohr%5C%25E2%5C%2580%5C%2593Mollerup_theorem