The Central Idea
An algorithm is a sequence of explicit instructions for carrying out a task.
Numerical algorithms often follow the pattern
\[ \boxed{ \text{initialize} \longrightarrow \text{compute} \longrightarrow \text{test} \longrightarrow \text{repeat or stop} }. \]Pseudocode makes this structure visible before implementation details are introduced.
What Is Pseudocode?
Pseudocode is a structured description of an algorithm written in ordinary mathematical and computational language.
It is not tied to the exact syntax of a programming language.
For example:
set x = 2
set y = x^2 + 1
display y
The intent is clear even though no specific programming language has been named.
Why Use Pseudocode?
Pseudocode helps separate two questions:
- What should the algorithm do?
- How does a particular language express those instructions?
This makes it useful for mathematics, planning, teaching, debugging, and translating an idea into software.
Variables in Pseudocode
A variable stores a value that may be used or changed later.
For example:
set x = 5
set y = 3
set total = x + y
After these instructions,
\[ \boxed{\text{total}=8}. \]Assignment
In an algorithm, an instruction such as
set x = x + 1
does not mean the algebraic equation
\[ x=x+1. \]It means:
Replace the current stored value of \(x\) with one more than its old value.
Assignment changes a stored value.
Old Value and New Value
Suppose
\[ x=7. \]After
set x = x + 3
the new value is
\[ \boxed{x=10}. \]The \(x\) on the right side refers to the old stored value during the update.
Input, Processing, and Output
Many algorithms can be organized into three stages:
\[ \boxed{ \text{input} \longrightarrow \text{processing} \longrightarrow \text{output} }. \]For example:
read radius
area = pi * radius^2
display area
Sequence
The simplest control structure is a sequence.
Instructions are carried out in order:
read x
square = x * x
result = square - 5
display result
Changing the order can change the result.
Branches
A branch allows an algorithm to choose different actions according to a condition.
A common form is:
if condition
do action A
else
do action B
Only one branch is followed during a particular execution.
Boolean Conditions
A branch condition must evaluate as true or false.
Examples include:
\[ x>0, \] \[ f(a)f(b)<0, \] \[ |x_{n+1}-x_n|<10^{-6}, \] \[ n\ge100. \]Example: Sign Classification
if x > 0
display "positive"
else if x < 0
display "negative"
else
display "zero"
The algorithm distinguishes three mutually exclusive cases.
Branches in Bisection
Bisection depends on a branch.
After computing the midpoint \(m\):
if f(m) = 0
return m
else if f(a)f(m) < 0
b = m
else
a = m
The branch determines which half of the interval is retained.
Nested Branches
A branch may contain another branch.
For example:
if x is in the domain
if abs(f(x)) < tolerance
accept x
else
continue iteration
else
stop with failure
Nested logic should remain readable and deliberate.
Loops
A loop repeats a block of instructions.
Numerical methods rely heavily on loops because the same update is often performed many times.
For example:
repeat
x = g(x)
until stopping condition is satisfied
Count-Controlled Loops
A count-controlled loop repeats a known number of times.
for n from 1 to 10
compute next approximation
This is useful when a fixed number of iterations has been chosen in advance.
Condition-Controlled Loops
A condition-controlled loop continues while or until a mathematical condition is met.
while error > tolerance
compute next approximation
The number of repetitions is determined by the computation itself.
While Loops
A while loop checks its condition before performing the next repetition.
while abs(f(x)) > tolerance
x = update(x)
If the condition is false initially, the loop may execute zero times.
Repeat-Until Loops
A repeat-until structure performs the update first and checks afterward.
repeat
new_x = update(x)
x = new_x
until abs(f(x)) < tolerance
This structure executes the body at least once.
The Loop Invariant Idea
A useful algorithm often maintains some property throughout a loop.
In bisection, a key invariant is:
\[ \boxed{ f(a_n)f(b_n)<0 } \]together with continuity on the interval.
Each update should preserve the valid bracket.
Iteration Counters
Numerical loops should often track an iteration number:
n = 0
while not finished
perform update
n = n + 1
The counter measures computational effort and supports maximum-iteration safeguards.
Stopping Conditions
A stopping condition specifies when repeated computation should end.
Common numerical conditions include:
\[ |x_{n+1}-x_n|<\varepsilon, \] \[ |f(x_n)|<\varepsilon, \] \[ b_n-a_n<\varepsilon, \]or
\[ n\ge N_{\max}. \]Tolerance
A tolerance is a numerical threshold used to decide when an approximation is sufficiently accurate for the purpose.
For example,
\[ \boxed{\varepsilon=10^{-6}} \]may be used as a stopping threshold.
Stopping by Successive Difference
For iterative values
\[ x_0,x_1,x_2,\ldots, \]one common test is
\[ \boxed{ |x_{n+1}-x_n|<\varepsilon }. \]This detects when the latest update is small.
Stopping by Residual
When solving
\[ f(x)=0, \]another condition is
\[ \boxed{ |f(x_n)|<\varepsilon }. \]This directly tests how closely the current approximation satisfies the equation.
Stopping by Interval Width
For a bracketing method, stop when
\[ \boxed{ b_n-a_n<\varepsilon }. \]This provides direct information about how tightly the root has been localized.
Maximum Iteration Conditions
Every iterative numerical algorithm should consider what happens if convergence never occurs.
A safeguard is:
\[ \boxed{ n\ge N_{\max} }. \]Once the limit is reached, the algorithm stops and reports failure or nonconvergence.
Success and Failure Are Different Stops
Numerical algorithms can terminate for different reasons.
A successful stop may mean:
\[ |f(x_n)|<\varepsilon. \]A failure stop may mean:
\[ f'(x_n)=0 \]or
\[ n=N_{\max}. \]Good pseudocode distinguishes successful completion from failure.
Compound Conditions
Several conditions can be combined.
For example:
if abs(new_x - x) < x_tolerance
and abs(f(new_x)) < residual_tolerance
return new_x
Both conditions must be satisfied.
AND Conditions
A condition
\[ A\text{ AND }B \]is true only when both \(A\) and \(B\) are true.
This is useful when an algorithm requires several independent indicators of convergence.
OR Conditions
A condition
\[ A\text{ OR }B \]is true when at least one of the conditions is true.
For example, a loop might stop when either convergence occurs or the maximum iteration count is reached.
Negation
A loop may continue while a stopping condition is not satisfied.
while not converged
perform another iteration
Logical negation is common in algorithm design.
Example: Successive Approximation Algorithm
Suppose we repeatedly update
\[ x_{n+1}=g(x_n). \]A basic algorithm is:
x = initial_guess
n = 0
repeat
new_x = g(x)
n = n + 1
if abs(new_x - x) < tolerance
return new_x
x = new_x
until n = maximum_iterations
report failure
Example: Fixed-Point Algorithm with Residual
x = initial_guess
n = 0
repeat
new_x = g(x)
n = n + 1
if abs(new_x - x) < x_tolerance
and abs(f(new_x)) < residual_tolerance
return new_x
x = new_x
until n = maximum_iterations
report nonconvergence
Example: Bisection Algorithm
input a, b
if f(a)f(b) >= 0
report "invalid bracket"
stop
repeat
m = (a + b) / 2
if f(m) = 0
return m
if f(a)f(m) < 0
b = m
else
a = m
until b - a < tolerance
return (a + b) / 2
Checking Continuity Is Conceptual, Not Always Mechanical
Bisection depends on continuity, but an algorithm cannot always determine continuity merely by sampling values.
The user or larger mathematical model must establish that the function is continuous on the interval.
Algorithms often rely on mathematical assumptions supplied from outside the code itself.
Example: Newton's Method Algorithm
x = initial_guess
n = 0
repeat
fx = f(x)
dfx = derivative(x)
if abs(dfx) < derivative_threshold
report "derivative too small"
stop
new_x = x - fx / dfx
n = n + 1
if abs(new_x - x) < x_tolerance
and abs(f(new_x)) < residual_tolerance
return new_x
x = new_x
until n = maximum_iterations
report nonconvergence
Why Test for a Small Derivative?
Newton's update contains
\[ \frac{f(x_n)}{f'(x_n)}. \]If
\[ |f'(x_n)| \]is extremely small, the correction can become extremely large.
A branch can detect this danger before performing the division.
Example: Secant Algorithm
x0 = first_guess
x1 = second_guess
n = 0
repeat
f0 = f(x0)
f1 = f(x1)
denominator = f1 - f0
if abs(denominator) < denominator_threshold
report "secant slope too small"
stop
x2 = x1 - f1 * (x1 - x0) / denominator
n = n + 1
if abs(x2 - x1) < x_tolerance
and abs(f(x2)) < residual_tolerance
return x2
x0 = x1
x1 = x2
until n = maximum_iterations
report nonconvergence
Loop State
The collection of values needed to continue an algorithm is its state.
For Newton's method, the state may include
\[ x_n \]and the iteration count.
For the secant method, the state includes
\[ x_{n-1},\qquad x_n. \]Updating State Correctly
In the secant method, after computing \(x_{n+1}\), update:
\[ x_{n-1}\leftarrow x_n, \] \[ x_n\leftarrow x_{n+1}. \]The order of assignment matters if old values are overwritten before they are reused.
Temporary Variables
Temporary variables can preserve old information during an update.
new_x = update(x)
error = abs(new_x - x)
x = new_x
This is clearer and safer than overwriting \(x\) before computing the difference.
Initialization
Every loop depends on correct initial values.
Numerical initialization may include:
- an initial guess \(x_0\);
- two secant guesses;
- a root bracket \([a,b]\);
- a tolerance;
- a maximum iteration count;
- an iteration counter beginning at \(0\).
Preconditions
A precondition is something that must be true before an algorithm begins.
Examples include:
\[ x_0\ne0, \]for an iteration containing \(1/x_n\), or
\[ f(a)f(b)<0, \]for standard sign-change bisection.
Postconditions
A postcondition describes what should be true after successful completion.
For a root solver, one possible postcondition is
\[ \boxed{|f(x)|<\varepsilon}. \]Postconditions make the meaning of “success” explicit.
Assertions
An assertion records a condition that should be true at a particular point in an algorithm.
For example, during bisection:
\[ \boxed{f(a)f(b)<0}. \]If the assertion fails unexpectedly, the implementation or assumptions should be investigated.
Infinite Loops
A loop that never reaches its stopping condition can continue indefinitely.
This may happen because:
- the algorithm diverges;
- the tolerance is unreachable;
- the stopping test is incorrect;
- the state is not being updated;
- roundoff prevents further improvement.
Guarding against Infinite Loops
A maximum iteration count provides a basic safeguard:
while not converged and n < maximum_iterations
perform update
n = n + 1
The loop must eventually terminate because \(n\) cannot increase forever while remaining below the fixed maximum.
Off-by-One Errors
Iteration counts can be confusing.
If
\[ x_0 \]is the initial value, then one update produces
\[ x_1. \]Ten updates produce
\[ x_{10}. \]Clearly define whether the initial state counts as an iteration.
Stopping before or after the Update
Consider:
while error > tolerance
update
versus
repeat
update
until error <= tolerance
These structures check the condition at different times and can behave differently when the initial value already satisfies the tolerance.
Strict versus Non-Strict Inequalities
A stopping rule may be written as
\[ |f(x)|<\varepsilon \]or
\[ |f(x)|\le\varepsilon. \]The distinction matters exactly at the boundary.
Algorithms should use the intended comparison consistently.
Absolute and Relative Stopping Conditions
An absolute criterion is
\[ |x_{n+1}-x_n|<\varepsilon. \]A relative criterion may be
\[ \boxed{ \frac{|x_{n+1}-x_n|} {\max(1,|x_{n+1}|)} <\varepsilon }. \]Relative tests adapt better when values vary greatly in scale.
Stopping Conditions Should Match the Goal
Different numerical goals require different tests.
If the goal is to locate a root inside a narrow bracket, interval width is natural.
If the goal is to satisfy an equation, residual size is natural.
If the goal is to detect stabilization of an iteration, successive difference is useful.
One Test May Not Be Enough
Suppose successive iterates become equal because floating-point arithmetic can no longer distinguish them.
Then
\[ |x_{n+1}-x_n|=0 \]even if the residual is not acceptably small.
Multiple stopping tests can provide stronger protection.
Failure Conditions Are Part of the Algorithm
A robust numerical procedure asks not only
When have we succeeded?
but also
How can this process fail?
Failure detection is a normal part of algorithm design.
Examples of Failure Conditions
- division by zero;
- a derivative that is too small;
- a secant denominator that is too small;
- an invalid initial bracket;
- a value outside the permitted domain;
- overflow or non-finite numerical values;
- maximum iterations reached.
NaN and Infinite Values
Numerical software may produce special values representing undefined or unrepresentable results.
An algorithm should detect when a computed value is not finite before continuing blindly.
A failure branch can stop the procedure and report the problem.
Tracing an Algorithm
To understand pseudocode, make a table showing the state after each step.
For example:
| Iteration | \(x_n\) | Residual |
|---|---|---|
| \(0\) | \(2.000000\) | \(f(x_0)\) |
| \(1\) | \(x_1\) | \(f(x_1)\) |
| \(2\) | \(x_2\) | \(f(x_2)\) |
Tracing exposes both mathematical and logical errors.
Dry Runs
A dry run means executing an algorithm manually on a small example.
Before automating a numerical method, test:
- one ordinary case;
- one boundary case;
- one failure case when possible.
This often reveals mistakes before software hides them behind fast computation.
Common Error: Confusing Assignment with Equality
In mathematics,
\[ x=x+1 \]has no real solution.
In pseudocode,
x = x + 1
is an update instruction.
The contexts are different.
Common Error: Forgetting to Update the Loop Variable
Consider:
while error > tolerance
compute new_x
compute error
If \(x\) is never replaced by \(new_x\), the algorithm may repeat the same calculation forever.
Common Error: Testing the Wrong Quantity
A root solver intended to satisfy
\[ f(x)=0 \]should not accidentally test
\[ |x|<\varepsilon \]unless the root itself is expected to be near zero.
The stopping quantity must correspond to the numerical objective.
Common Error: No Maximum Iteration Count
A convergence-based loop can run indefinitely when convergence fails.
Include a maximum count unless termination is guaranteed by some other structure.
Common Error: Stopping on Failure as if It Were Success
Reaching
\[ N_{\max} \]does not mean an approximation has converged.
The algorithm should report something such as
maximum iterations reached; tolerance not satisfied
rather than silently returning the last value as successful.
Common Error: Ignoring Domain Restrictions
An update rule may produce an input outside its valid domain.
For example,
\[ x_{n+1}=\ln(x_n) \]requires
\[ x_n>0. \]A branch should detect invalid values before the next operation is attempted.
Common Error: Using Exact Equality with Floating-Point Values
Testing
if f(x) = 0
can be appropriate when an exact zero happens to occur, but numerical algorithms should not rely only on exact floating-point equality.
A tolerance test such as
\[ |f(x)|<\varepsilon \]is usually more appropriate for approximate computation.
A Reliable Algorithm-Design Workflow
- State the mathematical goal.
- Identify required inputs.
- Identify the state that must be stored.
- Write the computational update.
- List mathematical preconditions.
- Add branches for special and failure cases.
- Choose success stopping conditions.
- Add a maximum-iteration safeguard when needed.
- Trace the algorithm manually on sample cases.
- Define what output constitutes success or failure.
Example: Full Root-Finding Pseudocode
The following pattern captures many iterative solvers:
input initial data
input tolerance
input maximum_iterations
initialize state
n = 0
while n < maximum_iterations
check failure conditions
compute next state
n = n + 1
compute step measure
compute residual measure
if convergence conditions are satisfied
report solution
stop
update state
report "nonconvergence"
Practice 1: Assignment
If \(x\) currently stores \(4\), what value does it store after
x = x + 3
Practice 2: Branch
What control structure should be used when an algorithm must choose one action if
\[ x>0 \]and another action otherwise?
Practice 3: Loop Type
Which type of loop is most natural when an update should continue until
\[ |f(x)|<10^{-6}? \]Practice 4: Bisection Branch
Suppose
\[ f(a)<0,\qquad f(m)>0. \]Which half should bisection retain?
Practice 5: Successive-Difference Stop
Does the condition
\[ |x_{n+1}-x_n|<0.001 \]hold if
\[ x_n=2.2360 \]and
\[ x_{n+1}=2.2367? \]Practice 6: Maximum Iterations
Why should a numerical iteration often include a maximum iteration count?
Practice 7: Newton Failure Branch
What quantity should be checked before dividing in Newton's update
\[ x_{n+1} = x_n-\frac{f(x_n)}{f'(x_n)}? \]Practice 8: Compound Condition
If an algorithm requires both a small step and a small residual, should the two conditions be joined by AND or OR?
Practice 9: Off-by-One
If \(x_0\) is the initial value, which iterate is obtained after three updates?
Practice 10: Verification
After pseudocode reports a numerical root \(x\), what mathematical quantity should usually be checked?
Practice Answers
Practice 1
The old value is \(4\), so the update stores
\[ 4+3=7. \]Therefore,
\[ \boxed{x=7}. \]Practice 2
Use a
\[ \boxed{\text{branch}} \]such as an if-else structure.
Practice 3
A condition-controlled loop is natural because the number of iterations is not known in advance.
Practice 4
Since the signs differ between \(a\) and \(m\), keep
\[ \boxed{[a,m]}. \]Practice 5
\[ |2.2367-2.2360| = 0.0007. \]Since
\[ 0.0007<0.001, \]the condition is satisfied.
Practice 6
It prevents a nonconvergent or incorrectly designed loop from running indefinitely and provides a clear failure condition.
Practice 7
Check
\[ \boxed{f'(x_n)}. \]The derivative must not be zero or dangerously small.
Practice 8
Use
\[ \boxed{\text{AND}}, \]because both requirements must be satisfied.
Practice 9
Starting from \(x_0\):
\[ x_0\to x_1\to x_2\to x_3. \]Therefore, three updates produce
\[ \boxed{x_3}. \]Practice 10
Evaluate the residual
\[ \boxed{f(x)} \]and confirm that its magnitude is sufficiently small.
What to Remember
- Pseudocode describes algorithms independently of programming-language syntax.
- Sequence executes instructions in order.
- Branches choose among alternatives according to true-or-false conditions.
- Loops repeat a block of computation.
- Numerical methods often use condition-controlled loops.
- Stopping conditions can use successive differences, residuals, interval widths, or other error measures.
- Maximum iteration counts protect against nontermination.
- Success conditions and failure conditions should be distinguished explicitly.
- State, initialization, update order, and domain restrictions all affect correctness.
- A numerical algorithm should be traced and verified rather than treated as a black box.
Where We Go Next
Pseudocode gives us a precise language for expressing numerical methods. The final step is to evaluate what those algorithms actually produce: Do the approximations converge? How much error remains? What tolerance is justified? How do we know the reported result is reliable?
The next lesson, Convergence, Error, Tolerance, and Verification, brings these ideas together and develops the standards used to judge numerical results.