Skip to content
academia.sh

Lesson 03 / 25

Little o and Little omega

Definitions of non-tight bounds, the limit criterion, the analogy between the five notations and comparison operators, and the limits of the ordering relation.

Contents

Big O gives an upper bound but does not say whether the bound is tight. The function nn is both O(n)O(n) and O(n2)O(n^2); the second statement is true but uninformative.

In some cases, what needs to be said is stronger: “ff grows strictly slower than gg.” This lesson defines the two notations that make that statement possible.

Little o

f(n)=o(g(n))    c>0, n0:nn0, f(n)<cg(n)f(n) = o(g(n)) \iff \forall c > 0,\ \exists n_0 : \forall n \geq n_0,\ f(n) < c \cdot g(n)

Its difference from big O is in the quantifier. Big O says “a cc exists”; little o says “for every cc” — no matter how small the constant is chosen, the inequality holds for sufficiently large nn.

The result is that ff becomes increasingly negligible next to gg. An equivalent and useful form is given with a limit:

f(n)=o(g(n))    limnf(n)g(n)=0f(n) = o(g(n)) \iff \lim_{n \to \infty} \frac{f(n)}{g(n)} = 0

For example, n=o(n2)n = o(n^2), because the ratio 1/n01/n \to 0. By contrast, 3n3n is not o(n)o(n): the ratio stays at the constant 33, it does not go to zero. Big O, however, accepts both — 3n=O(n)3n = O(n) is true.

Little omega

f(n)=ω(g(n))    limnf(n)g(n)=f(n) = \omega(g(n)) \iff \lim_{n \to \infty} \frac{f(n)}{g(n)} = \infty

Little omega is little o’s mirror image: ff strictly outpaces gg. n2=ω(n)n^2 = \omega(n) and 2n=ω(n100)2^n = \omega(n^{100}) are true — exponential growth eventually overtakes every polynomial.

The Analogy of the Five Notations

The five notations map one to one onto numeric comparisons:

Notation Comparison analogy Limit criterion
f=O(g)f = O(g) fgf \leq g Ratio finite (can be zero)
f=Ω(g)f = \Omega(g) fgf \geq g Ratio greater than zero (can be infinite)
f=Θ(g)f = \Theta(g) f=gf = g Ratio tends to a finite constant greater than zero
f=o(g)f = o(g) f<gf < g Ratio tends to zero
f=ω(g)f = \omega(g) f>gf > g Ratio tends to infinity

The analogy is instructive but not exact; the differences are taken up in the final section of this lesson.

Applying the Limit Criterion

The limit is the most practical way to determine the relationship between two functions. The ratio is computed and its behavior as it tends to infinity is examined.

import math

def ratio(f, g, n_values):
    return [f(n) / g(n) for n in n_values]

n_values = [10, 100, 1_000, 10_000, 100_000]

print([f"{x:.4f}" for x in ratio(lambda n: n, lambda n: n**2, n_values)])
# ['0.1000', '0.0100', '0.0010', '0.0001', '0.0000']   — tends to zero: n = o(n²)

print([f"{x:.4f}" for x in ratio(lambda n: 3*n, lambda n: n, n_values)])
# ['3.0000', '3.0000', '3.0000', '3.0000', '3.0000']   — constant: 3n = Θ(n), not o(n)

print([f"{x:.4f}" for x in ratio(math.log2, lambda n: n, n_values)])
# ['0.3322', '0.0664', '0.0100', '0.0013', '0.0002']   — tends to zero: log n = o(n)

print([f"{x:.2f}" for x in ratio(lambda n: n * math.log2(n), lambda n: n**2, n_values)])
# ['0.33', '0.07', '0.01', '0.00', '0.00']             — n log n = o(n²)

A numerical observation is not a proof; that the limit actually goes to zero is shown mathematically. But it is a fast way to confirm an expectation and catch errors.

The third line confirms a frequently used result: a logarithm grows slower than every positive power. The fourth line shows why the difference between nlognn \log n and n2n^2 is so decisive — the ratio tends to zero, meaning the gap widens as the input grows.

Growth Hierarchy

Little o arranges frequently used functions into a strict chain. At every step, the one on the left is little o of the one on the right:

1=o(loglogn)=o(logn)=o(nε)=o(n)=o(nlogn)=o(n2)=o(2n)=o(n!)1 = o(\log \log n) = o(\log n) = o(n^{\varepsilon}) = o(n) = o(n \log n) = o(n^2) = o(2^n) = o(n!)

Here ε\varepsilon is any constant greater than zero. The chain summarizes three general rules:

  • Logarithm grows slower than every positive power. Even logn=o(n0.001)\log n = o(n^{0.001}) holds; it does not matter how many times the logarithm is applied.
  • Every polynomial grows slower than every exponential. n1000=o(1.001n)n^{1000} = o(1.001^n) holds, no matter how close the base is to one.
  • Exponential grows slower than factorial. The average of n!n!’s factors grows along with nn, while 2n2^n’s factors stay constant.

Because every relation in the chain is written with little o, the distinctions between them are strict; moving from one class to another is not a constant-factor improvement but a change of order.

The same chain also gives the link between Θ\Theta and the little notations: if f=Θ(g)f = \Theta(g), then ff is neither o(g)o(g) nor ω(g)\omega(g). The three cases are mutually exclusive and — if the limit of the ratio exists — together cover every possibility.

What It Is For

Little notations are used in three places.

Establishing the class hierarchy. The statements “logn=o(n)\log n = o(n) and n=o(n2)n = o(n^2)” say that complexity classes are strictly separated. The same claim cannot be made with big O; because OO may be loose, it does not demonstrate the distinction.

Stating negligibility. If an expression’s smaller term is written with o()o(\cdot), this states “this term is asymptotically insignificant”: the expression n2+o(n2)n^2 + o(n^2) states that the second term vanishes next to the dominant term.

A claim of strict separation. That two algorithms are in different classes can only be stated with little notation. “The first is O(n2)O(n^2), the second is O(nlogn)O(n \log n)” does not by itself prove the second is better — the first’s bound might be loose. The precise statement is that the second algorithm’s cost is o()o(\cdot) of the first’s.

Not a Total Order

The comparison analogy breaks down at one point: for numbers, one of two values is always either smaller than, larger than, or equal to the other. For functions, there is no such guarantee.

Two functions can be incomparable: if the ratio between them oscillates, neither a limit exists nor can a bound relation be established. For example, there is no asymptotic relation at all between nn and a function that takes the value n2n^2 at odd nn and 11 at even nn.

def oscillating(n: int) -> int:
    return n**2 if n % 2 == 1 else 1

print([oscillating(n) / n for n in range(1, 8)])
# [1.0, 0.5, 3.0, 0.25, 5.0, 0.16666666666666666, 7.0]   — ratio oscillates

The ratio converges to neither zero nor infinity; it goes back and forth between them. Such a function is neither O(n)O(n) nor Ω(n)\Omega(n).

Algorithm costs encountered in practice are regular functions, and this problem does not arise; but knowing that the notation is a partial order requires constructing statements carefully.

Summary

  • Little o states that a bound is strictly loose: the inequality holds for every constant, and the ratio tends to zero.
  • Little omega is the same relation in reverse; the ratio tends to infinity.
  • The five notations resemble numeric comparisons: OO \approx \leq, Ω\Omega \approx \geq, Θ=\Theta \approx =, o<o \approx <, ω>\omega \approx >.
  • The limit criterion is the practical way to determine the relationship between two functions.
  • Little notations are used to establish the class hierarchy, state negligibility, and make a claim of strict separation.
  • The relation is not a total order; functions whose ratio oscillates are incomparable.

Next Step

The notations have been defined; next comes the growth classes they represent. The next lesson will compare, numerically, the classes stretching from constant time to factorial, and answer the question “how large an input can an algorithm handle.”

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ Esc navigate · open · close