Python
PRACTICAL LAB EXAM GUIDE · TOPICS 2 – 8
Python for
Scientific Computing
Every line explained. What it is, why it exists, how to use it — then real
exam-level problems.
Calculator & I/O Modules Control Structures Series & Taylor File Handling
User Functions Bisection Newton-Raphson
CALCULATOR I/O MODULES STRINGS/LISTS CONTROL SERIES FILES FUNCTIONS BISECTION N
TOPIC 2 · PART A
Python as a Number Calculator
WHAT WHY HOW TO START
Python's interactive shell No need to write a full Type python3 in terminal
(REPL) works like a program for a quick → you see >>> prompt.
scientific calculator — calculation. Perfect for That's the interactive
type an expression, press trying out formulas, mode. Every line is
Enter, get the result verifying physics answers. executed immediately.
instantly.
▸ Basic Arithmetic — Every Operator Explained
Python Interactive Shell — Arithmetic
# Addition
>>> 3 + 4
7
# Subtraction
>>> 10 - 3.5
6.5
# Multiplication
>>> 6 * 7
42
# Division — ALWAYS gives float result
>>> 7 / 2
3.5
# Integer (floor) division — discards remainder
>>> 7 // 2
3
# Modulo — gives REMAINDER
>>> 7 % 2
1
# Power (exponentiation) — NOTE: Python uses ** not ^
>>> 2 ** 10
1024
# Complex number arithmetic — Python handles them natively!
>>> (2 + 3j) * (1 - 2j)
(8-1j)
# Order of operations follows BODMAS
>>> 2 + 3 * 4
14 # multiplication first
>>> (2 + 3) * 4
20 # brackets first
# Underscore _ holds the last result
>>> 5 * 9
45
>>> _ + 5
50
OPERATOR NAME WHAT IT DOES EXAMPLE → OUTPUT
+ Addition Adds two numbers 3+4 → 7
- Subtraction Subtracts right from left 10-3 → 7
* Multiplication Multiplies 3*4 → 12
/ True division Always returns float 7/2 → 3.5
// Floor division Divides, discards decimal 7//2 → 3
% Modulo Returns remainder 7%2 → 1
** Exponentiation Power — use instead of ^ 2**8 → 256
j Imaginary unit Creates complex number 3+4j → (3+4j)
▸ Variables and Assignment
Variables
# Variable: a name that stores a value
# Python is dynamically typed — no need to declare type
>>> x = 5 # integer
>>> y = 3.14 # float
>>> name = "Alice" # string
>>> flag = True # boolean
# Multiple assignment in one line
>>> a, b, c = 1, 2, 3
# Check type of a variable
>>> type(x)
<class 'int'>
>>> type(y)
<class 'float'>
# Formula example: kinetic energy KE = ½mv²
>>> m = 2.0 # mass in kg
>>> v = 5.0 # velocity in m/s
>>> KE = 0.5 * m * v**2
>>> KE
25.0
TOPIC 2 · PART B
Standard I/O — input, print
WHAT IS PRINT() WHAT IS INPUT() WHY NEEDED
print() sends output to input() pauses and waits Programs need to
the screen. It's the main for the user to type communicate with users
way to display results. something, then returns it — output shows results,
as a string. input takes data. Every
interactive program uses
both.
▸ print() — Every Option Explained
print() usage
# Simplest use — print a string
print("Hello World")
Hello World
# Print a variable
x = 42
print(x)
42
# Print multiple items — default separator is space
print("x =", x, "and x² =", x**2)
x = 42 and x² = 1764
# sep= changes the separator between items
print(1, 2, 3, sep=",")
1,2,3
# end= changes what's printed at the end (default is newline \n)
print("Loading", end="...")
print("Done")
Loading...Done
# f-string (formatted string) — most modern way to format output
name = "Physics"
val = 9.81
print(f"g = {val} m/s² in {name}")
g = 9.81 m/s² in Physics
# Format numbers: .4f = 4 decimal places
print(f"π ≈ {3.14159265:.4f}")
π ≈ 3.1416
# Scientific notation
print(f"Planck's constant = {6.626e-34:.3e}")
Planck's constant = 6.626e-34
▸ input() — Reading User Input
input() usage
# input() ALWAYS returns a string — must convert for numbers
# Read a name (string — no conversion needed)
name = input("Enter your name: ")
print(f"Hello, {name}!")
# Read an integer — wrap with int()
n = int(input("Enter integer: "))
# Read a float — wrap with float()
mass = float(input("Enter mass (kg): "))
velocity = float(input("Enter velocity (m/s): "))
KE = 0.5 * mass * velocity**2
print(f"Kinetic Energy = {KE:.2f} J")
# Read multiple values on one line using split()
a, b = map(float, input("Enter two numbers: ").split())
print(f"Sum = {a+b}")
FUNCTION WHAT WHY CRITICAL NOTE
print(x) Displays x on Show results to user Accepts multiple items
screen separated by commas
input("msg") Reads one line of Take data from user Always returns string —
user input interactively convert with int() or float()
int(x) Converts x to Convert input string to Crashes if x is not a valid
integer usable number integer
float(x) Converts x to For physics calculations Crashes if x is not a valid
decimal number needing decimals number
f"... f-string formatting Clean, readable output with Put f before the quote. Use
{var}..." variables embedded {var:.Nf} for decimals.
TOPIC 2 · PART C
Importing Modules — math & cmath
WHAT IS A MODULE WHY IMPORT CMATH MODULE
A module is a file of ready- Python's basic arithmetic Like math but works with
made functions and doesn't include sin, cos, complex numbers. Use
constants. You import it sqrt, pi etc. The math [Link](-1) → 1j
to use those functions module provides all without an error.
without writing them scientific functions.
yourself.
▸ math Module — All Key Functions
math module
# Three ways to import:
# Method 1: import whole module — access with [Link]
import math
print([Link](16)) # → 4.0
# Method 2: from module import specific function
from math import sqrt, sin, cos, pi
print(sqrt(25)) # → 5.0 (no 'math.' prefix needed)
# Method 3: import all (convenient but can cause name clashes)
from math import *
# ── Constants ───────────────────────────────────
import math
print([Link]) # 3.141592653589793
print(math.e) # 2.718281828459045 (Euler's number)
print([Link]) # infinity
print([Link]) # 2π
# ── Trigonometry (argument in RADIANS) ──────────
print([Link]([Link]/2)) # 1.0 (sin 90°)
print([Link](0)) # 1.0 (cos 0°)
print([Link]([Link]/4)) # 1.0 (tan 45°)
# Convert degrees to radians before using trig!
angle_deg = 30
angle_rad = [Link](angle_deg)
print([Link](angle_rad)) # 0.5
# Convert back: radians to degrees
print([Link]([Link])) # 180.0
# ── Powers and Logs ─────────────────────────────
print([Link](144)) # 12.0
print([Link](2, 10)) # 1024.0
print([Link](math.e)) # 1.0 (natural log)
print(math.log10(1000)) # 3.0 (log base 10)
print(math.log2(8)) # 3.0 (log base 2)
print([Link](1)) # 2.718... = e^1
# ── Rounding and misc ───────────────────────────
print([Link](3.7)) # 3 (round down)
print([Link](3.2)) # 4 (round up)
print([Link](5)) # 120
print([Link](12, 8)) # 4
print([Link](-5.5)) # 5.5 (absolute value)
print([Link](3,4)) # 5.0 (√(3²+4²))
▸ cmath Module — Complex Numbers
cmath module
import cmath
# Works on complex numbers where math would crash
print([Link](-1)) # 1j (imaginary unit)
print([Link](-4)) # 2j
# Phase (angle) and magnitude (modulus) of a complex number
z = 3 + 4j
print(abs(z)) # 5.0 (modulus |z|)
print([Link](z)) # angle in radians
# Polar form: (r, θ)
r, theta = [Link](z)
print(f"r={r:.2f}, θ={theta:.4f} rad")
# Convert polar back to rectangular
print([Link](r, theta)) # → (3+4j) approximately
# Complex exponential (Euler's formula: e^(iθ) = cos θ + i sin θ)
import cmath
theta = [Link] / 2
print([Link](1j * theta)) # ≈ (0 + 1j) = i
# help() — search for functions
help([Link]) # shows documentation for sin
dir(math) # lists all functions in math module
Using help() in interactive mode: Type help(math) to see all functions. Type help([Link]) to see
what sqrt does, its arguments and return type. This is the built-in documentation system — use it
during your exam if you forget a function name.
TOPIC 2 · PART D
Strings, Lists & Tuples
▸ Strings
Strings — creation, slicing, methods
# String: sequence of characters, enclosed in quotes
s = "Hello Python"
# ── Indexing (0-based — first character is index 0) ──
print(s[0]) # H
print(s[6]) # P
print(s[-1]) # n (last character)
print(s[-2]) # o (second from last)
# ── Slicing: s[start : stop : step] ──────────────
# stop is EXCLUDED; step is optional
print(s[0:5]) # Hello (characters 0,1,2,3,4)
print(s[6:]) # Python (from index 6 to end)
print(s[:5]) # Hello (from start to index 4)
print(s[::2]) # HloPto (every 2nd character)
print(s[::-1]) # nohtyP olleH (reversed string)
# ── Key String Methods ────────────────────────────
print([Link]()) # HELLO PYTHON
print([Link]()) # hello python
print([Link]("Hello", "Hi")) # Hi Python
print([Link](" ")) # ['Hello', 'Python']
print([Link]("Python")) # 6 (index where found)
print(len(s)) # 12 (length)
print([Link]()) # removes leading/trailing spaces
print([Link]("Hello")) # True
print(" ".join(["a","b","c"])) # a b c
▸ Lists
Lists — mutable sequences
# List: ordered, mutable (changeable) collection
# Used for storing a series of data — e.g. experimental measurements
data = [10.2, 11.5, 9.8, 12.1, 10.9]
# ── Indexing and Slicing (same as strings) ───────
print(data[0]) # 10.2
print(data[-1]) # 10.9
print(data[1:3]) # [11.5, 9.8]
# ── Modifying Lists (unlike strings, lists are mutable) ──
data[0] = 10.5 # change first element
[Link](13.0) # add element to end
[Link](2, 11.0) # insert 11.0 at index 2
[Link](9.8) # remove first occurrence of 9.8
[Link]() # removes and returns last element
[Link]() # sort in ascending order
[Link]() # reverse in place
# ── Useful built-ins on lists ─────────────────────
print(len(data)) # number of elements
print(sum(data)) # sum of all elements
print(max(data)) # largest element
print(min(data)) # smallest element
# ── List Comprehension — create lists in one line ─
squares = [x**2 for x in range(1, 6)]
print(squares) # [1, 4, 9, 16, 25]
# ── range() — generates a sequence of integers ───
print(list(range(5))) # [0, 1, 2, 3, 4]
print(list(range(1, 6))) # [1, 2, 3, 4, 5]
print(list(range(0, 10, 2))) # [0, 2, 4, 6, 8] (step=2)
▸ Tuples
Tuples — immutable sequences
# Tuple: like a list but IMMUTABLE (cannot be changed)
# Use when data should NOT be modified — e.g. constants
point = (3.0, 4.0) # 2D point (x, y)
RGB = (255, 128, 0) # colour — fixed values
# Indexing — same as list
print(point[0]) # 3.0
print(point[1]) # 4.0
# Unpacking — assign each element to a variable
x, y = point
print(f"x={x}, y={y}")
# Tuples are faster than lists and protect data from accidental change
# point[0] = 5 ← this would CRASH — tuples are immutable
# Functions can return multiple values via tuple
def min_max(lst):
return min(lst), max(lst) # returns a tuple
lo, hi = min_max([3, 1, 4, 1, 5])
print(lo, hi) # 1 5
Key difference: List [...] → mutable (can change values). Tuple (...) → immutable (cannot
change). Use list for data you'll process; use tuple for fixed coordinates, constants, or returning
multiple values from functions.
TOPIC 2 · PART E
Control Structures — if, for, while, try-except
▸ if / elif / else — Decision Making
Conditionals
# if: execute block only if condition is True
# INDENTATION (4 spaces) defines the block — Python has NO braces {}
x = float(input("Enter temperature (°C): "))
if x < 0:
print("Below freezing")
elif x == 0:
print("Exactly at freezing point")
elif x < 100:
print("Liquid water")
else:
print("Above boiling point")
# Comparison operators: == != < > <= >=
# Logical operators: and or not
if x >= 0 and x <= 100:
print("Normal range")
▸ for Loop — Iterate Over a Sequence
for loop
# for: repeat for each item in a sequence
# Most common loop in scientific programming
# Loop over a range
for i in range(1, 6):
print(i, i**2) # prints i and i²
# Loop over a list
temperatures = [20.1, 22.3, 19.8, 21.0]
total = 0
for t in temperatures:
total += t # total = total + t
mean = total / len(temperatures)
print(f"Mean = {mean:.2f}")
# enumerate: gives index AND value together
for i, val in enumerate(temperatures):
print(f"T[{i}] = {val}")
# Nested for: multiplication table
for i in range(1, 4):
for j in range(1, 4):
print(i*j, end=" ")
print() # newline after each row
# break: exit loop early; continue: skip to next iteration
for i in range(10):
if i == 5: break # stops at i=5
if i % 2 == 0: continue # skips even numbers
print(i)
▸ while Loop — Repeat Until Condition is False
while loop
# while: keep looping as long as condition remains True
# Use when you DON'T know in advance how many iterations are needed
# Perfect for iterative methods (bisection, Newton-Raphson)
# Example: sum digits until sum > 20
total = 0
n = 1
while total <= 20:
total += n
n += 1
print(f"Sum exceeded 20 at n={n-1}, sum={total}")
# Convergence loop (used in numerical methods)
x = 1.0
tolerance = 1e-6
while True:
x_new = (x + 2.0/x) / 2 # Newton's method for sqrt(2)
if abs(x_new - x) < tolerance:
break
x = x_new
print(f"sqrt(2) ≈ {x:.8f}") # 1.41421356
▸ try / except — Error Handling
try-except
# try: attempt the code; except: handle the error if it crashes
# WHY: prevents program from crashing when bad input is given
try:
x = float(input("Enter a number: "))
result = 1.0 / x
print(f"1/{x} = {result}")
except ValueError:
print("Error: Please enter a valid number")
except ZeroDivisionError:
print("Error: Cannot divide by zero")
finally:
print("This always runs") # runs whether or not error occurred
# Common exception types:
# ValueError → wrong type of value (e.g. int("hello"))
# ZeroDivisionError → dividing by zero
# FileNotFoundError → file doesn't exist
# IndexError → list index out of range
# TypeError → wrong type of argument
TOPIC 3
Series Summation & Taylor Expansion
WHAT WHY
A series is a sum of many terms following a Many physical quantities (electric
pattern. Python computes these with a potential, wave functions,
loop, adding one term at a time. thermodynamics) are expressed as infinite
series. Computing them numerically is
essential in science.
▸ AP, GP, Power Series
Arithmetic & Geometric Progression Sums
# ── AP: sum = n/2 * (2a + (n-1)d) ───────────────
# But compute term by term to demonstrate the method:
print("=== Arithmetic Progression ===")
a = float(input("First term a: "))
d = float(input("Common difference d: "))
n = int(input("Number of terms n: "))
total = 0
for i in range(n):
term = a + i * d # i-th term of AP
total += term
print(f"Sum of {n} terms of AP = {total}")
# ── GP: sum = a * (r^n - 1) / (r - 1) ───────────
print("=== Geometric Progression ===")
a = float(input("First term a: "))
r = float(input("Common ratio r: "))
n = int(input("Number of terms n: "))
total = 0
term = a
for i in range(n):
total += term
term *= r # next term = current term × r
print(f"Sum of {n} terms of GP = {total}")
▸ Taylor Series — sin(x) from scratch
Taylor series for sin(x) and comparison with [Link]
# Taylor series: sin(x) = x - x³/3! + x⁵/5! - x⁷/7! + ...
# General term: (-1)^n * x^(2n+1) / (2n+1)!
# We stop when the term becomes smaller than a tolerance
import math
def my_sin(x, tol=1e-10):
"""Compute sin(x) using Taylor series until convergence."""
total = 0.0
term = x # first term is just x
n = 0
while abs(term) > tol:
total += term
n += 1
# Each term = previous term * (-x²) / ((2n)(2n+1))
term *= (-x**2) / ((2*n) * (2*n + 1))
return total
# Test and compare
for x_deg in [0, 30, 45, 60, 90]:
x_rad = [Link](x_deg)
my_val = my_sin(x_rad)
lib_val = [Link](x_rad)
error = abs(my_val - lib_val)
print(f"sin({x_deg:3d}°) my={my_val:.8f} lib={lib_val:.8f} err={error:.2e}")
# Output:
sin( 0°) my=0.00000000 lib=0.00000000 err=0.00e+00
sin( 30°) my=0.50000000 lib=0.50000000 err=1.11e-16
sin( 90°) my=1.00000000 lib=1.00000000 err=1.11e-16
▸ Taylor Series for e^x (Exponential)
Taylor series: e^x = 1 + x + x²/2! + x³/3! + ...
import math
def my_exp(x, tol=1e-10):
total = 1.0 # zeroth term is 1
term = 1.0
n = 1
while abs(term) > tol:
term *= x / n # term_n = term_{n-1} * x/n
total += term
n += 1
return total
print(f"my_exp(1) = {my_exp(1):.10f}") # should be e = 2.7182818285
print(f"math.e = {math.e:.10f}") # compare
TOPIC 4
File Handling in Python
WHAT WHY MODES
Python can read data from Experimental data lives in "r" = read, "w" = write
files and write results to text files. You read them in (overwrites), "a" =
files. Files persist after the Python, process them append, "r+" =
program ends — essential (statistics, fitting), and read+write
for lab data processing. output results to new files.
▸ Opening and Reading Files — Every Line Explained
File I/O — Reading
# ── Method 1: open() with close() ─────────────────
f = open("[Link]", "r") # open for reading
content = [Link]() # read entire file as one string
[Link]() # MUST close to free memory
# ── Method 2: with statement (BEST PRACTICE) ──────
# with automatically closes file even if error occurs
with open("[Link]", "r") as f:
content = [Link]() # read whole file
# file is auto-closed when 'with' block ends
# ── Reading line by line ────────────────────────────
with open("[Link]", "r") as f:
for line in f: # iterate over lines
line = [Link]() # remove newline \n at end
print(line)
# ── Read all lines into a list ──────────────────────
with open("[Link]", "r") as f:
lines = [Link]() # list of strings, one per line
▸ Syllabus Example 1 — Three Column Data: Sum & Standard Deviation
Read x,y,z file → sum and std dev of y and z
# [Link] has three columns: x, y, z (space-separated)
# 0.0 1.23 4.56
# 1.0 2.34 5.67
# ...
import math
y_vals = []
z_vals = []
with open("[Link]", "r") as f:
for line in f:
line = [Link]()
if [Link]("#") or line == "":
continue # skip comment and blank lines
parts = [Link]() # split by whitespace → list of strings
x = float(parts[0]) # column 1
y = float(parts[1]) # column 2
z = float(parts[2]) # column 3
y_vals.append(y)
z_vals.append(z)
# Compute sum
def my_sum(lst): return sum(lst)
# Compute standard deviation (population std dev)
def std_dev(lst):
n = len(lst)
mean = sum(lst) / n
variance = sum((xi - mean)**2 for xi in lst) / n
return [Link](variance)
print(f"Sum of y = {my_sum(y_vals):.4f}")
print(f"Sum of z = {my_sum(z_vals):.4f}")
print(f"Std Dev of y = {std_dev(y_vals):.4f}")
print(f"Std Dev of z = {std_dev(z_vals):.4f}")
▸ Syllabus Example 2 — Frequency Table of Integers
Single-column integers → frequency table → output to file
# [Link] has 20+ integers, one per line
# e.g.: 3 5 2 3 7 5 3 2 ...
# Step 1: Read integers
nums = []
with open("[Link]", "r") as f:
for line in f:
[Link](int([Link]()))
# Step 2: Build frequency dictionary
freq = {}
for num in nums:
if num in freq:
freq[num] += 1 # already seen → increment count
else:
freq[num] = 1 # first time seen → count = 1
# Step 3: Write frequency table to output file
with open("[Link]", "w") as out:
[Link]("Number\tFrequency\n") # header line
for num in sorted(freq): # sorted by number
[Link](f"{num}\t{freq[num]}\n")
print("Frequency table written to [Link]")
# Step 4: Also display on screen
print("Number Frequency")
for num in sorted(freq):
print(f"{num:6d} {freq[num]:6d}")
Writing to a file: [Link](string) — writes a string (must add \n for new lines yourself). "w" mode
overwrites the file. "a" mode appends to existing content.
TOPIC 6
User Defined Functions in Python
WHAT IS A FUNCTION WHY USE FUNCTIONS DEFAULT ARGUMENTS
A reusable named block of Breaks large programs Parameters can have
code. Define once with into small, manageable default values — caller
def , call many times. pieces. Easier to test, doesn't need to provide
Avoids repeating code. debug, and reuse in them unless they want a
different programs. different value.
GLOBAL VARIABLES
Variables declared outside
functions are global.
Inside a function, use
global x to modify a
global variable.
▸ Anatomy of a Function — Every Line Explained
Function syntax
# def keyword: starts function definition
# function_name: your chosen name (use lowercase_with_underscores)
# parameters: inputs the function receives
# return: sends a value back to the caller
def kinetic_energy(mass, velocity):
"""Compute kinetic energy: KE = 0.5 * m * v²
Args:
mass: mass in kg
velocity: speed in m/s
Returns:
Kinetic energy in Joules
"""
KE = 0.5 * mass * velocity**2
return KE
# Call the function
energy = kinetic_energy(2.0, 10.0) # positional arguments
print(energy) # 100.0
# Keyword arguments — order doesn't matter
energy2 = kinetic_energy(velocity=10.0, mass=2.0)
print(energy2) # 100.0
▸ Syllabus Functions — All Four Required
i) Double factorial f(x) = x!!
# Double factorial: n!! = n × (n-2) × (n-4) × ... × 1 (or 2)
# e.g. 7!! = 7×5×3×1 = 105, 6!! = 6×4×2 = 48
# Application: appears in quantum mechanics, wave functions
def double_factorial(n):
"""Returns n!! (double factorial)"""
if n <= 1:
return 1 # base cases: 0!! = 1, 1!! = 1
result = 1
while n > 1:
result *= n
n -= 2 # decrease by 2 each step
return result
for i in range(0, 10):
print(f"{i}!! = {double_factorial(i)}")
ii) f(n) = nth Fibonacci number
# Fibonacci: 0, 1, 1, 2, 3, 5, 8, 13, 21, ...
# F(n) = F(n-1) + F(n-2), F(0)=0, F(1)=1
# Application: population growth, golden ratio, nature patterns
def fibonacci(n):
"""Returns nth Fibonacci number (0-indexed)."""
if n < 0:
raise ValueError("n must be non-negative")
if n == 0: return 0
if n == 1: return 1
a, b = 0, 1
for _ in range(2, n+1):
a, b = b, a+b # swap and update in one step
return b
for i in range(10):
print(f"F({i}) = {fibonacci(i)}")
iii) linspace(start, stop, number=50) — default argument
# linspace: returns 'number' evenly spaced values from start to stop
# Default argument: number=50 means caller can omit it
# This mimics numpy's linspace for basic use
def linspace(start, stop, number=50):
"""Generate 'number' evenly spaced values from start to stop (inclusive).
Args:
start : first value
stop : last value
number : count of values (DEFAULT = 50)
Returns:
list of floats
"""
if number < 2:
return [start]
step = (stop - start) / (number - 1) # spacing between points
return [start + i * step for i in range(number)]
# Use with all three arguments
pts = linspace(0, 1, 5)
print(pts) # [0.0, 0.25, 0.5, 0.75, 1.0]
# Use with default number=50
pts2 = linspace(0, [Link])
print(len(pts2)) # 50
iv) f(a,x) = exp(-ax)sin(x) with a as GLOBAL variable
import math
# Global variable — defined outside all functions
# Accessible everywhere in the script
a = 0.3 # damping constant — GLOBAL
def f(x):
"""Damped sine wave using global 'a'.
f(x) = exp(-a*x) * sin(x)
"""
# global a is READ here — no 'global' keyword needed just to read
return [Link](-a * x) * [Link](x)
# Test
for x in linspace(0, 10, 6):
print(f"f({x:.2f}) = {f(x):.6f}")
# Changing global a changes the function's behaviour
print("\nWith a = 0.1 (less damping):")
a = 0.1 # change global
print(f([Link]))
# If you need to MODIFY global inside a function, use global keyword:
def reset_damping():
global a # declares we're modifying the global 'a'
a = 0.5 # now this changes the global variable
TOPIC 7
Bisection Method — Root Finding
WHAT WHY IT WORKS APPLICATIONS
The Bisection method If f(a) < 0 and f(b) > 0, Find when a projectile hits
finds the root (zero) of a there must be a root ground. Find temperature
function f(x) by repeatedly between a and b at which two curves meet.
halving an interval [a,b] (Intermediate Value Any nonlinear equation.
where f(a) and f(b) have Theorem). Keep halving
opposite signs. until the interval is tiny.
Algorithm: 1) Pick a, b where f(a)·f(b) < 0. 2) Find midpoint m = (a+b)/2. 3) If f(m)=0, done. If f(a)·f(m) <
0, root is in [a,m] so b=m. Else root is in [m,b] so a=m. 4) Repeat until |b−a| < tolerance.
Bisection Method — complete implementation
import math
def bisection(f, a, b, tol=1e-8, max_iter=100):
"""
Find root of f(x) = 0 in interval [a, b] by bisection.
Args:
f : the function whose root we seek
a, b : initial bracket (f(a)*f(b) must be < 0)
tol : tolerance (stop when interval width < tol)
max_iter : safety limit on iterations
Returns:
midpoint : approximate root
n_iter : number of iterations used
"""
if f(a) * f(b) > 0:
raise ValueError("f(a) and f(b) must have opposite signs!")
print(f"{'Iter':<5} {'a':<14} {'b':<14} {'midpoint':<14} {'f(mid)':<14}")
print("-" * 65)
for n in range(1, max_iter + 1):
mid = (a + b) / 2 # midpoint of interval
fmid = f(mid)
print(f"{n:<5} {a:<14.8f} {b:<14.8f} {mid:<14.8f} {fmid:<14.4e}")
if abs(fmid) < tol or (b - a) / 2 < tol:
return mid, n # converged!
if f(a) * fmid < 0:
b = mid # root in left half [a, mid]
else:
a = mid # root in right half [mid, b]
return (a + b) / 2, max_iter
# ── Example 1: find root of x³ - x - 2 = 0 ──────
def g(x): return x**3 - x - 2
root, iters = bisection(g, 1, 2)
print(f"\nRoot = {root:.8f} (in {iters} iterations)")
print(f"Verification: g({root:.6f}) = {g(root):.2e}")
# ── Example 2: find time when projectile returns to ground ──
# x(t) = v0*t - 0.5*g*t² = 0 (not at t=0, find the other root)
v0 = 20.0 # initial velocity m/s
g = 9.81
def height(t): return v0*t - 0.5*g*t**2
# From plot we know root is between t=1 and t=5
time_land, _ = bisection(height, 1, 5)
print(f"\nProjectile lands at t = {time_land:.4f} s")
print(f"Exact: t = {2*v0/g:.4f} s") # analytical answer
TOPIC 8
Newton-Raphson Method
WHAT FORMULA WHY FASTER
Newton-Raphson finds x₁ = x₀ − f(x₀)/f'(x₀) — start Bisection halves the error
roots much faster than at x₀, subtract f/f', repeat each step. Newton-
bisection by using the until converged. Raphson squares the
derivative (slope) to accuracy — near the root,
predict where the root is. each step doubles the
number of correct digits
(quadratic convergence).
LIMITATION
Needs a good starting
guess x₀. Can fail if f'(x₀) =
0 or if the function is badly
behaved. Use a plot to find
a good initial guess.
Newton-Raphson — complete implementation
import math
def newton_raphson(f, df, x0, tol=1e-10, max_iter=50):
"""
Find root of f(x) = 0 using Newton-Raphson method.
Args:
f : function f(x)
df : derivative f'(x) — you must provide this
x0 : initial guess (use plot to choose)
tol : convergence tolerance
max_iter: safety limit
Returns:
x : approximate root
n : iterations used
"""
x = x0
print(f"{'Iter':<5} {'x':<18} {'f(x)':<16} {'f\\'(x)':<14} {'|step|':<12}")
print("-" * 65)
for n in range(1, max_iter + 1):
fx = f(x)
dfx = df(x)
if abs(dfx) < 1e-14:
raise ZeroDivisionError("Derivative is zero — Newton fails here")
step = fx / dfx # Newton step = f(x) / f'(x)
x_new = x - step # update rule: x = x - f(x)/f'(x)
print(f"{n:<5} {x:<18.12f} {fx:<16.6e} {dfx:<14.4f} {abs(step):<12.4e}")
if abs(step) < tol:
return x_new, n # converged
x = x_new
return x, max_iter
# ── Example 1: solve x³ - x - 2 = 0 ─────────────
def g(x): return x**3 - x - 2
def dg(x): return 3*x**2 - 1 # derivative of g
root, iters = newton_raphson(g, dg, x0=1.5)
print(f"\nRoot = {root:.12f} ({iters} iterations)")
# ── Example 2: solve cos(x) = x (transcendental) ─
# Rearrange: f(x) = cos(x) - x = 0
def h(x): return [Link](x) - x
def dh(x): return -[Link](x) - 1
root2, iters2 = newton_raphson(h, dh, x0=0.5)
print(f"\nSolution of cos(x)=x: x = {root2:.12f} ({iters2} iterations)")
# Famous Dottie number ≈ 0.739085133
# ── Example 3: physical problem ───────────────────
# Find angle θ at which projectile range R = R0
# R = v0² sin(2θ)/g = R0
# f(θ) = v0² sin(2θ)/g - R0 = 0
v0 = 30.0; g_val = 9.81; R0 = 60.0
def range_eq(theta):
return v0**2 * [Link](2*theta) / g_val - R0
def d_range_eq(theta):
return 2 * v0**2 * [Link](2*theta) / g_val
theta_sol, _ = newton_raphson(range_eq, d_range_eq, x0=[Link]/6)
print(f"\nLaunch angle = {[Link](theta_sol):.4f}°")
METHOD CONVERGENCE RATE NEEDS WHEN TO USE
Bisection Linear (1 bit/step) Bracket [a,b] only Always works if bracket found. Slow
but guaranteed.
Newton- Quadratic (doubles Good x₀ AND Much faster, but needs derivative and
Raphson digits) derivative f'(x) good starting point.
PRACTICAL EXAM
External Exam — Lab-Level Questions
Write complete, working Python programs for each question. Follow good coding practices:
meaningful variable names, comments, formatted output.
PART A Python as Calculator & I/O
Q1 — Formula Cruncher
Write a Python program that takes the following inputs from the user: initial velocity u
(m/s), acceleration a (m/s²), and time t (s). Compute and display: (i) Final velocity: v = u +
at (ii) Distance: s = ut + ½at² (iii) Kinetic energy at time t (mass m = 5 kg) Display all results
with 4 decimal places and appropriate units.
[8 marks]
Q2 — Temperature Converter
Write a program that accepts a temperature and a unit ("C", "F", or "K") from the user and
converts it to the other two scales. Use if-elif-else. Add input validation using try-except
to handle non-numeric input gracefully. Formulae: F = 9/5·C + 32, K = C + 273.15.
[10 marks]
Hint: Always convert to Celsius first, then to the other two. Use try-except to catch ValueError if the
user types letters instead of a number.
Q3 — Complex Number Operations
Using the cmath module, write a program that: (a) Takes two complex numbers z₁ and z₂
from the user (real and imaginary parts separately) (b) Computes z₁+z₂, z₁−z₂, z₁×z₂, z₁/z₂ (c)
Displays modulus and phase of each result (d) Verifies Euler's formula: e^(iπ) + 1 ≈ 0
[10 marks]
PART B Control Structures & Loops
Q4 — Prime Sieve
Write a program to find and print all prime numbers up to N (input by user). Use a nested
loop: for each number n from 2 to N, check if any number from 2 to √n divides it. Use the
math module for sqrt. Count how many primes there are and display the result.
[8 marks]
Q5 — Pascal's Triangle
Write a program to generate and display Pascal's Triangle up to n rows (input by user).
Store each row as a list. Each element = sum of two elements above it. Print the triangle in
centred format. Also print the binomial coefficients of the last row.
[10 marks]
Q6 — Collatz Conjecture
The Collatz sequence starting from n: if n is even → n/2; if n is odd → 3n+1. Repeat until
reaching 1. Write a program that: (a) computes the Collatz sequence for any input n, (b)
counts how many steps it takes, (c) finds which starting number below 1000 takes the
most steps. Use a while loop.
[10 marks]
PART C Series Summation & Taylor Expansion
Q7 — cos(x) by Taylor Series
Write a Python function my_cos(x, tol=1e-10) that computes cos(x) using the Taylor
series: cos(x) = 1 − x²/2! + x⁴/4! − x⁶/6! + ... Stop when the absolute value of the next term is
less than tol. Test your function for x = 0°, 30°, 60°, 90°, 180° (convert to radians first).
Compare each result with [Link]() and print the error. Count the number of terms
needed.
[12 marks]
Q8 — Power Series: ln(1+x)
The Taylor series for ln(1+x) for |x| < 1 is: ln(1+x) = x − x²/2 + x³/3 − x⁴/4 + ... (a) Write my_ln(x,
tol=1e-8) to compute this series. Add a check that |x| < 1 and raise ValueError otherwise.
(b) Test for x = 0.1, 0.5, 0.9 and compare with [Link](1+x) . (c) Demonstrate
convergence by printing the running sum after each term.
[12 marks]
PART D File Handling
Q9 — Lab Data Processor
A file lab_data.txt has three columns: x (position in m), y (voltage in V), z (current in
mA), separated by spaces. Write a program that: (a) Reads all three columns into
separate lists (b) Computes mean, variance, and standard deviation of y and z (without
using statistics module — write formulas yourself) (c) Computes the correlation
coefficient between y and z: r = Σ(yᵢ−ȳ )(zᵢ−z̄ ) / √[Σ(yᵢ−ȳ )² · Σ(zᵢ−z̄ )²] (d) Writes a summary
report to [Link] (e) Handle missing/corrupt lines using try-except
[15 marks]
Q10 — Word Frequency Counter
Read a text file [Link] . Count the frequency of each unique word (case-
insensitive, ignore punctuation). Write the output to word_freq.txt with two columns:
word and count, sorted by frequency in descending order. Print the top 10 most frequent
words on screen.
[12 marks]
Hint: Use [Link](), [Link]() to clean text. Use a dictionary for counting. Use sorted(dict,
key=lambda k: dict[k], reverse=True) to sort by value.
PART E User Functions, Bisection & Newton-Raphson
Q11 — Complete Function Library
Write the following user-defined functions in a single script: (a) factorial(n) — using a
loop (not recursion), raise ValueError for negative n (b) double_factorial(n) — as
defined in syllabus (c) fibonacci_list(n) — returns a list of first n Fibonacci numbers (d)
linspace(a, b, n=100) — with default n=100 (e) my_sin(x, tol=1e-10) — Taylor series for
sin Test each function with at least 3 inputs and print formatted results.
[15 marks]
Q12 — Root Finding: Bisection vs Newton-Raphson
Consider the equation: f(x) = x·e^x − 3 = 0. (a) Plot mentally (or describe) where the root
lies. (b) Find the root using your bisection function with initial bracket [0, 2]. (c) Find the
root using Newton-Raphson with x₀ = 1.0. (Derivative: f'(x) = eˣ + xeˣ = eˣ(1+x)) (d)
Compare: number of iterations, final root value, final error |f(root)|. (e) Explain in
comments why Newton-Raphson converges faster.
[15 marks]
Q13 — Physical Application: Pendulum Period
The exact period of a pendulum is T = 4√(L/g) · K(sin(θ/2)) where K is the complete elliptic
integral. For small angles, T₀ = 2π√(L/g). The correction satisfies: T/T₀ = 1 + (1/16)θ² +
(11/3072)θ⁴ + ... Write a program that: (a) Defines a function period_ratio(theta_deg)
computing T/T₀ using the first 4 terms of the series (b) Finds the angle θ at which T/T₀ =
1.01 (1% error) using bisection (c) Tests for L=1.0m: compute T₀ and T_exact for that angle
(d) Uses Newton-Raphson to also solve f(θ) = T/T₀ − 1.01 = 0 and compare
[18 marks]
Hint: θ should be in radians inside the series. Use bisection with bracket [0.01, 1.5] for the angle in
radians.
QUICK REFERENCE
Python Cheat Sheet
Quick Reference
── TYPES ──────────────────────────────────────────────────
int(x) float(x) str(x) complex(a,b) bool(x)
type(x) isinstance(x, int)
── INPUT / OUTPUT ─────────────────────────────────────────
x = input("msg") # always returns string
x = float(input("msg")) # read a float
print(f"{x:.4f}") # 4 decimal places
print(f"{x:.3e}") # scientific notation
── MATH MODULE ────────────────────────────────────────────
import math
[Link] math.e [Link](x) [Link](x) [Link](x)
[Link](x) [Link](x) [Link](n)
[Link](deg) [Link](rad)
── LISTS ──────────────────────────────────────────────────
lst = [1,2,3] [Link](x) [Link]() sum(lst)
lst[a:b] lst[::step] lst[::-1] len(lst) max(lst)
── CONTROL FLOW ───────────────────────────────────────────
if cond: elif cond: else:
for i in range(n):
while cond: break continue
try: except Exception: finally:
── FUNCTIONS ──────────────────────────────────────────────
def f(x, default=10): # default argument
global var # modify global
return result
── FILES ──────────────────────────────────────────────────
with open("[Link]", "r") as f: # read
for line in f: ...
with open("[Link]", "w") as f: # write
[Link](f"data\n")
── ROOT FINDING ───────────────────────────────────────────
# Bisection: needs f(a)*f(b) < 0; mid=(a+b)/2; halve interval
# Newton: x_new = x - f(x)/f'(x); quadratic convergence
Python Complete Tutorial · Syllabus Topics 2–8
Calculator · I/O · Modules · Strings/Lists · Control · Series · Files · Functions · Bisection ·
Newton-Raphson