Chapter 2
12 min read
Section 17 of 353

Infinite Limits: Vertical Asymptotes

Limits - Approaching the Infinite

Learning Objectives

By the end of this section you will be able to:

  1. Describe what it means for a limit to be infinite — and why that is not the same as "the limit exists".
  2. State the formal definition of limxaf(x)=+\displaystyle\lim_{x\to a}f(x)=+\infty and its one-sided cousins.
  3. Identify vertical asymptotes of common functions by hand.
  4. Classify the four canonical behaviors at a vertical asymptote.
  5. Compute vertical asymptotes for rational functions algebraically.
  6. Connect vertical asymptotes to exploding gradients in machine learning.

The Big Picture

In the previous section we watched f(x)f(x) approach a finite height as xx\to\infty. We now flip the script. The input stays finite — it slides toward some ordinary number aa — but the output refuses to settle anywhere. It grows bigger, and bigger, and bigger, without bound. The graph shoots up (or down) a forbidden vertical line and never comes back.

Core idea

An infinite limit happens when the value of a function f(x)f(x) escapes every bounded window as xx approaches a specific point aa. The vertical line x=ax=a is called a vertical asymptote — a height the function hugs but never crosses.

This is the second fundamental way a limit can misbehave:

  • Finite limitf(x)Lf(x)\to L, a nice real number. Example: sinxx1\frac{\sin x}{x}\to 1.
  • Infinite limitf(x)±f(x)\to\pm\infty. Example: 1x2+\frac{1}{x^{2}}\to+\infty as x0x\to 0.
  • No limit at all — the function oscillates or the two sides disagree. Example: sin(1/x)\sin(1/x) near 0.

When we say "the limit is infinity" we are not claiming that the limit exists. Infinity is not a real number. We are recording the specific way the limit fails to exist — the function leaves every ceiling behind.


Intuition: Growing Without Bound

Picture sliding your finger along the x-axis toward a fixed point aa. At each x you peek at the height of the graph. Normally those heights cluster around some value. Sometimes though, the heights don't cluster — they run away.

A cartoon. Imagine standing on a trampoline next to a column that reaches the ceiling. The closer you walk toward the column, the more the trampoline floor slopes up. One step before the column the floor is at your knees. A centimetre before the column the floor is above your head. A millimetre before, the floor pokes through the ceiling. That column is a vertical asymptote.

Concretely, for f(x)=1/xf(x)=1/x near x=0x=0:

xf(x) = 1/x
0.52
0.110
0.01100
0.0011,000
0.000110,000
0.00001100,000

No single number is the limit. For any ceiling you pick — 1010, 10610^{6}, 1010010^{100} — the function eventually pokes through it. That unbounded escape is what we mean by f(x)+f(x)\to+\infty.


Interactive Exploration

Pick a function. Move the asymptote with the first slider. Then shrink ε\varepsilon — the distance between the probe points and aa — and watch the two boxed values race off to infinity. The red dashed line marks the forbidden vertical:

Loading interactive explorer…

Things to try

  • Start with f(x)=1/(xa)f(x)=1/(x-a) and shrink ε\varepsilon. Left and right boxes disagree in sign — the two-sided limit does not exist.
  • Switch to 1/(xa)21/(x-a)^{2}. Both sides agree: the function hugs ++\infty.
  • Try lnxa\ln|x-a|. It dives to -\infty, but watch how much slower — at ε=103\varepsilon=10^{-3} the magnitude is only about 7.

Formal Definition of Infinite Limits

The informal idea "output grows without bound" is turned into hard mathematics by reversing the roles of ε\varepsilon and δ\delta from the ordinary limit definition. Instead of forcing the output into a band, we ask: for any target ceiling M, can we force the output above M by pushing x close enough to a?

Two-sided, tending to +∞

We write limxaf(x)=+\displaystyle\lim_{x\to a}f(x)=+\infty to mean: for every real number M>0M>0 there exists δ>0\delta>0 such that

0<xa<δ    f(x)>M.\displaystyle 0<|x-a|<\delta \;\Longrightarrow\; f(x)>M.

"Name any ceiling MM — I'll give you a horizontal tolerance δ\delta so that once xx is within δ\delta of aa (but not equal), f(x)f(x) sits above your ceiling."

Two-sided, tending to −∞

We write limxaf(x)=\displaystyle\lim_{x\to a}f(x)=-\infty to mean: for every real number N<0N<0 there exists δ>0\delta>0 such that

0<xa<δ    f(x)<N.\displaystyle 0<|x-a|<\delta \;\Longrightarrow\; f(x)<N.

Same story, but the floor goes arbitrarily deep.

One-sided versions

Replace 0<xa<δ0<|x-a|<\delta with either

  • aδ<x<aa-\delta<x<a for the left-hand limit limxaf(x)\displaystyle\lim_{x\to a^{-}}f(x), or
  • a<x<a+δa<x<a+\delta for the right-hand limit limxa+f(x)\displaystyle\lim_{x\to a^{+}}f(x).

The one-sided limits can be ++\infty, -\infty, a real number, or nothing at all. The two-sided limit agrees only when both sides match.

“The limit does not exist” vs “the limit is infinity”

These two statements mean different things. lim=+\lim = +\infty is a specific description of how a limit fails to be finite. lim\lim DNE (does not exist) is the broader term: it includes infinite limits, oscillations, and one-sided mismatches.


Seeing It in Numbers

Formal statements are reassuring, but tables make the idea visceral. Pick a function and watch what happens as h=x2h=|x-2| shrinks by a factor of 10 each row:

Loading table…

Worked Example 1 — A Simple Pole

Compute the one-sided limits of

f(x)=1x2\displaystyle f(x)=\frac{1}{x-2}

as x2x\to 2, and decide whether the two-sided limit exists.

Expand step-by-step walkthrough

Step 1 — Left-hand side. Let x=2hx=2-h with h>0h>0. Then x2=hx-2=-h, so

f(2h)=1h=1h.\displaystyle f(2-h)=\frac{1}{-h}=-\frac{1}{h}.

As h0+h\to 0^{+}, we have 1/h+1/h\to +\infty, hence f(2h)f(2-h)\to -\infty.

limx21x2=.\displaystyle\lim_{x\to 2^{-}}\frac{1}{x-2}=-\infty.

Step 2 — Right-hand side. Let x=2+hx=2+h. Then x2=+hx-2=+h, so

f(2+h)=1hh0++.\displaystyle f(2+h)=\frac{1}{h}\xrightarrow{h\to 0^{+}}+\infty.
limx2+1x2=+.\displaystyle\lim_{x\to 2^{+}}\frac{1}{x-2}=+\infty.

Step 3 — Combine. Left says -\infty, right says ++\infty. The two sides disagree, so the two-sided limit does not exist. The vertical line x=2x=2 is a vertical asymptote.

Step 4 — Sanity check with numbers. Plug h=0.001h=0.001 into the formulas: f(1.999)=1000f(1.999)=-1000, f(2.001)=1000f(2.001)=1000. That matches the Python table below.


Four Flavors of Vertical Asymptote

Not every asymptote behaves the same way. By matching the left-hand and right-hand infinite limits, we get four canonical cases. Use the gallery below as a lookup table the next time you have to classify one:

Loading gallery…
CaseLeft-hand limitRight-hand limitTwo-sided verdict
I+∞+∞lim = +∞
II−∞−∞lim = −∞
III−∞+∞ (or swapped)DNE
IV (log-type)−∞−∞lim = −∞ (slow)

Cases I and II are the two cases where mathematicians allow themselves to write lim=±\lim=\pm\infty. In Case III the two sides disagree, so the limit does not exist at all — we must either pick a side or accept no answer.


Vertical Asymptotes — Definition

A function ff has a vertical asymptote at x=ax=a if at least one of the one-sided limits there is infinite:

limxaf(x)=±orlimxa+f(x)=±.\displaystyle \lim_{x\to a^{-}}f(x)=\pm\infty \quad\text{or}\quad \lim_{x\to a^{+}}f(x)=\pm\infty.

Notice the or: a single exploding one-sided limit is enough. The function lnx\ln x has a vertical asymptote at x=0x=0 even though only the right side 0+0^{+} makes sense — it dives to -\infty.

Asymptote ≠ unattainable

A vertical asymptote is a line the graph cannot cross, but the graph can equal it at isolated points elsewhere (think a horizontal asymptote being crossed by a decaying sine). For verticals, the rule is strict: the graph's height races off to infinity as xax\to a.


How to Find Vertical Asymptotes

Three families of functions cover 95% of the cases you meet:

1. Rational functions

For f(x)=p(x)/q(x)f(x)=p(x)/q(x), a vertical asymptote at x=ax=a happens when q(a)=0q(a)=0 and p(a)0p(a)\neq 0. If both numerator and denominator vanish, the zero might be a removable hole instead — you must cancel common factors first.

2. Logarithms

ln(u(x))\ln(u(x)) has a vertical asymptote wherever u(x)=0+u(x)=0^{+}. The logarithm's left side is undefined, so usually only a one-sided limit applies.

3. Trigonometric functions

tanx,  secx,  cscx,  cotx\tan x,\; \sec x,\; \csc x,\; \cot x have vertical asymptotes at every zero of their inner cosine or sine: tanx\tan x blows up at x=π2+kπx=\tfrac{\pi}{2}+k\pi.


Worked Example 2 — A Rational Function

Find all vertical asymptotes of

g(x)=x+1x24.\displaystyle g(x)=\frac{x+1}{x^{2}-4}.
Expand step-by-step walkthrough

Step 1 — Factor the denominator.

x24=(x2)(x+2).\displaystyle x^{2}-4=(x-2)(x+2).

Step 2 — Find candidate asymptotes. Denominator zeros: x=2x=2 and x=2x=-2.

Step 3 — Check the numerator.

  • At x=2x=2: p(2)=30p(2)=3\neq 0 → genuine asymptote.
  • At x=2x=-2: p(2)=10p(-2)=-1\neq 0 → genuine asymptote.

Step 4 — Sign analysis at x = 2. Near x=2x=2, the numerator is close to 3 (positive), (x+2)4(x+2)\approx 4 (positive), and the factor (x2)(x-2) carries the asymptote behavior:

g(x)34(x2).\displaystyle g(x)\approx\frac{3}{4(x-2)}.
  • x2x\to 2^{-}: (x2)0(x-2)\to 0^{-} gg\to -\infty.
  • x2+x\to 2^{+}: (x2)0+(x-2)\to 0^{+} g+g\to +\infty.

Same structure as Example 1 — Case III, two-sided DNE.

Step 5 — Sign analysis at x = −2. Numerator (2)+1=1(-2)+1=-1 (negative), (x2)4(x-2)\approx -4 (negative), so

g(x)14(x+2)=14(x+2).\displaystyle g(x)\approx\frac{-1}{-4\,(x+2)}=\frac{1}{4(x+2)}.
  • x2x\to -2^{-}: (x+2)0(x+2)\to 0^{-} gg\to -\infty.
  • x2+x\to -2^{+}: (x+2)0+(x+2)\to 0^{+} g+g\to +\infty.

Conclusion. Two vertical asymptotes: x=2x=2 and x=2x=-2. Both are Case III — sign flips across each one.


Python Implementation

Before reaching for a library, let's do the experiment by hand. Click any line below to see the actual value of every variable on that line — across all five iterations of the loop.

Plain Python — numerically approaching a vertical asymptote
🐍infinite_limit_plain.py
1Problem setup — probe f(x) = 1/(x − 2) near x = 2

This comment declares the experiment. We will evaluate f at points that creep toward the suspected asymptote x = 2 from both sides and watch the outputs. There is no magic — just Python arithmetic, but the values will scream 'something is wrong' as we get closer.

2def f(x): — the function under investigation

Defines a single-input function. Whenever we call f(something), Python substitutes 'something' for x inside the body. f is first-class: we can pass it around, store it, or graph it.

EXECUTION STATE
⬇ input: x = Any real number except 2. If x = 2, the computation below divides by zero and Python raises ZeroDivisionError.
⬆ returns = A float — the value 1/(x−2). Large in magnitude when x is near 2, small when x is far from 2.
3Docstring — behavior note

The triple-quoted string documents that the function is undefined at x = 2. This is not just a Python issue: the mathematical function itself has no value there, because 1/0 is not a real number.

4return 1 / (x - 2)

Computes the quotient. The subtraction (x − 2) runs first (Python's PEMDAS), and the result is divided into 1. If (x − 2) is tiny, we divide 1 by something close to 0, which produces a very large number.

EXECUTION STATE
(x - 2) = The horizontal offset from the asymptote. Example: at x=2.001, (x−2)=0.001; at x=1.999, (x−2)=−0.001.
/ = Python's floating-point division operator. 1/0.001 = 1000.0; 1/(-0.001) = -1000.0. Small denominator ⇒ large quotient.
⬆ return: 1 / (x - 2) = Sign follows (x − 2): positive when x > 2, negative when x < 2. Magnitude explodes as x → 2.
6a = 2 — location of the suspected asymptote

We fix the x-value we are sneaking up on. Using a variable keeps the code general: swap a = 2 for any other number and every formula below still works.

EXECUTION STATE
a = 2 (integer) — the x-value that makes the denominator zero.
7step_sizes = [1, 0.1, 0.01, 0.001, 0.0001]

A Python list of shrinking distances from the asymptote. Each entry is 10× smaller than the previous one — a geometric sequence that lets us watch a decade-by-decade pattern in the output.

EXECUTION STATE
step_sizes = [1, 0.1, 0.01, 0.001, 0.0001] — 5 distances, each 1/10 of the last.
→ why geometric? = Shrinking by 10× at each step mimics 'taking a limit': we never actually reach h = 0, but we get arbitrarily close, which is exactly the meaning of a limit.
9print(f"…") — table header

f-strings (formatted string literals) interpolate values inside {…} and allow alignment with the >8, >10, >14 specifiers. The > means right-align; the number is the column width. This produces a clean ASCII table.

EXECUTION STATE
📚 f"…" = Python f-string: any Python expression inside {curly braces} is evaluated and inserted. Example: h=1 → f"{h:>8}" yields the string ' 1'.
>8, >10, >14 = Format specifiers: '>' means right-align, the digit is the column width. Keeps rows aligned even when numbers have different lengths.
10for h in step_sizes: — iterate over shrinking steps

Runs the loop body once per element of step_sizes. Each iteration h is smaller, so x_left and x_right get progressively closer to the asymptote at a = 2.

LOOP TRACE · 5 iterations
iter 1 · h = 1
x_left = 2 − 1 = 1
x_right = 2 + 1 = 3
f_left = 1 / (1 − 2) = -1.0000
f_right = 1 / (3 − 2) = 1.0000
iter 2 · h = 0.1
x_left = 2 − 0.1 = 1.9
x_right = 2 + 0.1 = 2.1
f_left = 1 / (−0.1) = -10.0000
f_right = 1 / 0.1 = 10.0000
iter 3 · h = 0.01
x_left = 1.99
x_right = 2.01
f_left = 1 / (−0.01) = -100.0000
f_right = 1 / 0.01 = 100.0000
iter 4 · h = 0.001
x_left = 1.999
x_right = 2.001
f_left = 1 / (−0.001) = -1000.0000
f_right = 1 / 0.001 = 1000.0000
iter 5 · h = 0.0001
x_left = 1.9999
x_right = 2.0001
f_left = 1 / (−0.0001) = -10000.0000
f_right = 1 / 0.0001 = 10000.0000
11x_left = a - h — approach from below

Builds an x-coordinate just to the LEFT of the asymptote. Because h is positive, x_left is always less than a, so (x_left − a) is negative — which forces the final 1/(x−a) to be negative.

EXECUTION STATE
x_left = a − h = 2 − h. Across iterations: 1, 1.9, 1.99, 1.999, 1.9999. Each entry is closer to 2, but never equals 2.
12x_right = a + h — approach from above

Builds an x-coordinate just to the RIGHT of the asymptote. (x_right − a) = +h is positive, so 1/(x_right − a) = +1/h is positive.

EXECUTION STATE
x_right = a + h = 2 + h. Across iterations: 3, 2.1, 2.01, 2.001, 2.0001. Each closer to 2 from the right.
13f_left = f(x_left) — the left-side function value

Calls f with x = x_left. Because x_left < 2, the expression (x − 2) is negative, making 1/(x − 2) negative. As h → 0, x_left → 2⁻ and f_left → −∞.

EXECUTION STATE
f_left pattern = −1, −10, −100, −1000, −10000 (magnitude × 10 each step)
→ why ×10? = Because h shrinks by 10× each iteration, 1/h grows by 10×. This is the signature of a simple pole of order 1.
14f_right = f(x_right) — the right-side function value

Calls f with x = x_right. Because x_right > 2, (x − 2) is positive, so f_right is positive. As h → 0, x_right → 2⁺ and f_right → +∞.

EXECUTION STATE
f_right pattern = +1, +10, +100, +1000, +10000
→ left vs right = f_left and f_right are mirror images around zero. Their opposite signs prove the two-sided limit at x = 2 does NOT exist.
15print(f"…") — emit one row per iteration

Prints the current h, the two x-values, and the two function values, all nicely aligned. Running the script produces the table shown in the book and visually reveals the 'both magnitudes blowing up with opposite signs' pattern.

2 lines without explanation
1# Plain Python: watch f(x) = 1 / (x - 2) as x approaches 2
2def f(x):
3    """Has a vertical asymptote at x = 2."""
4    return 1 / (x - 2)
5
6a = 2                                 # asymptote location
7step_sizes = [1, 0.1, 0.01, 0.001, 0.0001]
8
9print(f"{'h':>8}  {'x=a-h':>10}  {'f(a-h)':>14}  {'x=a+h':>10}  {'f(a+h)':>14}")
10for h in step_sizes:
11    x_left  = a - h                   # approach from below
12    x_right = a + h                   # approach from above
13    f_left  = f(x_left)               # → negative
14    f_right = f(x_right)              # → positive
15    print(f"{h:>8}  {x_left:>10.5f}  {f_left:>14.4f}  {x_right:>10.5f}  {f_right:>14.4f}")

PyTorch: Why Asymptotes Break Training

Vertical asymptotes are not just a calculus curiosity — they are a very real failure mode in machine learning. When a loss function or one of its components passes near a pole, the value of the loss explodes, and the gradient explodes even faster (by one extra power). The next snippet makes that concrete: compute f(x)=1/(x2)f(x)=1/(x-2) and its gradient with PyTorch's autograd, then watch both race to infinity together.

PyTorch — forward value AND gradient both explode
🐍infinite_limit_pytorch.py
1import torch

Loads PyTorch. We need tensors (for batched evaluation) and autograd (for automatic differentiation). Nothing here is GPU-specific — we stay on the CPU.

EXECUTION STATE
📚 torch = PyTorch library: provides the Tensor type (n-dimensional array with autograd support), many math functions, and the nn module for neural networks.
3Comment — experiment description

We will evaluate f(x) = 1/(x − a) at a vector of x-values close to a, and also compute the derivative f'(x) = −1/(x − a)² via autograd. Both will blow up — the key lesson is that a division-by-near-zero breaks BOTH the value and the gradient.

4a = 2.0 — asymptote location

A plain Python float. Python's broadcasting rules let us write (x - a) where x is a tensor and a is a scalar; PyTorch silently promotes a into a 0-D tensor.

EXECUTION STATE
a = 2.0 (Python float)
6Comment — preparing x near the asymptote with autograd enabled

The next line builds the batch of probe points. We keep them all on the RIGHT of a so f will be positive and easy to read.

7x = torch.tensor([...], requires_grad=True)

Creates a 1-D tensor of 5 x-values and marks it as a leaf in the autograd graph. Every operation we do on x is recorded so PyTorch can later compute gradients via the chain rule.

EXECUTION STATE
📚 torch.tensor(data, requires_grad=...) = Factory that copies a Python list (or NumPy array) into a new tensor. If requires_grad=True, autograd tracks this tensor; .grad will be populated after a .backward() call.
⬇ arg 1: data = [2.1, 2.01, 2.001, 2.0001, 2.00001] — five x-values approaching 2 from above.
⬇ arg 2: requires_grad=True = Turns on gradient tracking for this tensor. Without this flag, backward() would not populate x.grad. Default is False, which is the right choice for raw data but WRONG for inputs you want to differentiate against.
⬆ result: x (shape [5], dtype float32) = [2.1000, 2.0100, 2.0010, 2.0001, 2.00001]
→ (x − a) across the batch = [0.1, 0.01, 0.001, 0.0001, 0.00001]
9Comment — forward pass

The forward pass computes the function value. Because x has requires_grad=True, every op is added to the computation graph as a node, ready for later differentiation.

10f = 1.0 / (x - a)

Elementwise computation: for each xi, compute 1/(xi − a). The subtraction broadcasts the scalar a across the 5-element tensor; the division also broadcasts the scalar 1.0. The result f has the same shape as x.

EXECUTION STATE
(x - a) = [0.1000, 0.0100, 0.0010, 0.0001, 0.00001]
1.0 / (x - a) = Element-wise reciprocal. f[i] = 1 / (x[i] − a).
⬆ result: f (shape [5]) = [10.0, 100.0, 1000.0, 10000.0, 100000.0]
→ pattern = Each time (x − a) shrinks by 10×, f grows by 10×. Classic signature of a first-order pole.
12Comment — backward pass preview

We are about to compute gradients. The comment reminds us of the expected analytic answer: d/dx [1/(x-a)] = -1/(x-a)². Autograd should agree.

13# d/dx [1/(x-a)] = -1/(x-a)^2

The hand-derived derivative. Obtained by the power rule: write 1/(x-a) as (x-a)^(-1), differentiate to get -(x-a)^(-2), which is −1/(x-a)². The sign is negative because the function is decreasing on each side of the asymptote.

14f.sum().backward() — run autograd

backward() propagates gradients from a SCALAR through the computation graph. Because f is a vector of length 5, we first reduce it with .sum() so there is a single output to differentiate. The partial derivative of sum(f) with respect to x[i] is exactly f'(x[i]), so x.grad ends up holding the per-element derivative.

EXECUTION STATE
📚 .sum() = Tensor method: reduces all elements to a single scalar by addition. Example: torch.tensor([1,2,3]).sum() = tensor(6).
📚 .backward() = Triggers reverse-mode automatic differentiation. Walks the graph from the output scalar back to every leaf tensor with requires_grad=True, accumulating the gradient into that leaf's .grad attribute.
→ why .sum() first? = backward() requires a scalar. Summing turns the length-5 f vector into a single number whose gradient w.r.t. x[i] is exactly df/dx[i]. Equivalent to passing a vector of ones as the output gradient.
⬆ side effect: x.grad populated = [-100.0, -10000.0, -1.0e6, -1.0e8, -1.0e10]
→ compare to analytic = −1/(x−a)² at x=2.1 gives −1/0.01 = −100. ✓ Autograd matches calculus exactly.
16print(header) — table column titles

An f-string with right-aligned columns. The '\\'' inside the string is an escaped apostrophe so Python doesn't think the string has ended.

17for xi, fi, gi in zip(x.tolist(), f.tolist(), x.grad.tolist()):

Iterates three lists in lockstep. .tolist() converts each tensor to a regular Python list (detached from autograd) so we can pull out individual floats for printing.

EXECUTION STATE
📚 .tolist() = Tensor method: copies tensor data into a (nested) Python list of floats/ints. Breaks the autograd link, which is fine here — we just want to print.
📚 zip(a, b, c) = Built-in: yields tuples (a[i], b[i], c[i]) one at a time. Stops at the shortest input. Perfect for walking several parallel lists together.
LOOP TRACE · 5 iterations
i=0 · x=2.1
xi = 2.10000
fi = 10.0000
|gi| = 100
i=1 · x=2.01
xi = 2.01000
fi = 100.0000
|gi| = 10,000
i=2 · x=2.001
xi = 2.00100
fi = 1,000.0000
|gi| = 1,000,000 (1e6)
i=3 · x=2.0001
xi = 2.00010
fi = 10,000.0000
|gi| = 100,000,000 (1e8)
i=4 · x=2.00001
xi = 2.00001
fi = 100,000.0000
|gi| = 10,000,000,000 (1e10)
18print(row) — format one tensor element per row

Prints x, f(x), and |f'(x)| side by side for each probe point. The :>14.4g specifier means right-aligned width 14 with 4-digit general (smart exponential when needed) precision — ideal for the huge gradient magnitudes.

5 lines without explanation
1import torch
2
3# Show both the value AND the gradient exploding near x = 2.
4a = 2.0
5
6# Tensor of x-values approaching 2 from the right; enable autograd.
7x = torch.tensor([2.1, 2.01, 2.001, 2.0001, 2.00001], requires_grad=True)
8
9# Forward pass: elementwise f(x) = 1 / (x - a)
10f = 1.0 / (x - a)
11
12# Backward pass: accumulates df/dx_i into x.grad.
13#   d/dx [1/(x-a)] = -1/(x-a)^2
14f.sum().backward()
15
16print(f"{'x':>10}   {'f(x)':>14}   {'|f\'(x)|':>14}")
17for xi, fi, gi in zip(x.tolist(), f.tolist(), x.grad.tolist()):
18    print(f"{xi:>10.5f}   {fi:>14.4f}   {abs(gi):>14.4g}")

Why this matters in ML

A 1/(xa)1/(x-a) in the forward pass becomes a 1/(xa)21/(x-a)^{2} in the backward pass. Where the value multiplies by 10 from one decade of proximity to the next, the gradient multiplies by 100. That is why a small numerical slip that letsxx drift too close to a pole produces NaNs in a neural network: the gradient becomes 101010^{10}, the update step overshoots by several orders of magnitude, and the next forward pass is unrecoverable.


Real-World Applications

🌌 Physics — Coulomb potential

The electric potential between two point charges is V(r)=kQ/rV(r)=kQ/r. As r0+r\to 0^{+}, VV\to\infty — the textbook reason we model point charges as limits.

🤖 Machine learning — log-likelihoods

Cross-entropy loss contains logp-\log p. If a predicted probability p0+p\to 0^{+}, the loss tends to ++\infty. That is why implementations clip pp away from 0 or use log_softmax for stability.

💰 Finance — leverage ratios

Debt-to-equity, price-to-earnings, and similar ratios all look like x/yx/y. As y0y\to 0 (a firm with vanishing earnings), the ratio explodes — a vertical asymptote disguised as a headline.

🛰️ Signal processing — tan and sec

The tangent function appears in angle-of-arrival formulas. Near π/2\pi/2, tanx\tan x has a vertical asymptote, and any algorithm that uses it must fall back to a different parametrization (for example atan2).


Common Pitfalls

“Cancelling” makes the asymptote disappear

For f(x)=(x21)/(x1)f(x)=(x^{2}-1)/(x-1), the denominator is zero at x=1x=1, but so is the numerator. Factor first: (x1)(x+1)/(x1)=x+1(x-1)(x+1)/(x-1)=x+1. That is a removable discontinuity, not a vertical asymptote. Always cancel common factors before declaring victory.

Two-sided limit vs one-sided limit

Writing limxaf(x)=+\lim_{x\to a}f(x)=+\infty requires both one-sided limits to be ++\infty. If left says -\infty and right says ++\infty, the two-sided limit does not exist — you must use one-sided notation.

Infinity isn't a number

You cannot write +=0+\infty - \infty = 0. Limits of the form \infty - \infty, 00\cdot\infty, or /\infty/\infty are indeterminate and need a trick (factoring, conjugates, L'Hôpital) to resolve.


Summary

IdeaFormula / Description
Infinite limitf(x) escapes every bound as x → a
Two-sided +∞∀ M > 0 ∃ δ > 0 : 0 < |x − a| < δ ⇒ f(x) > M
Two-sided −∞∀ N < 0 ∃ δ > 0 : 0 < |x − a| < δ ⇒ f(x) < N
Vertical asymptoteA line x = a where at least one one-sided limit is ±∞
Rational testq(a) = 0 AND p(a) ≠ 0 ⇒ vertical asymptote at a
Gradient connectionPole in f(x) of order k ⇒ pole in f'(x) of order k+1

Key Takeaways

  1. An infinite limit describes a specific way a limit fails to exist — the output grows past every ceiling.
  2. The formal definition reverses the roles of ε\varepsilon and MM: pick any ceiling, we'll give you a tolerance.
  3. Vertical asymptotes come in four flavors; the sign analysis determines which.
  4. Rational functions: factor, cancel, check numerator — then read off the asymptotes.
  5. In machine learning, a pole in the forward pass is a worse pole in the backward pass. Always clamp or reparametrize.
The Essence:
“A vertical asymptote is the place where a function's height is no longer trapped by any ceiling — the graph slips past every bound as x approaches a single forbidden point.”
Coming next: §2.5 introduces the ε–δ definition — the same "name-a-ceiling" game we just played, but played for finite limits. You'll see that the infinite-limit definition was the easier sibling all along.
Loading comments...