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:

  1. What should the algorithm do?
  2. 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:

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:

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

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:

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

  1. State the mathematical goal.
  2. Identify required inputs.
  3. Identify the state that must be stored.
  4. Write the computational update.
  5. List mathematical preconditions.
  6. Add branches for special and failure cases.
  7. Choose success stopping conditions.
  8. Add a maximum-iteration safeguard when needed.
  9. Trace the algorithm manually on sample cases.
  10. 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

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.