Variables: named boxes in memory
A variable is a named place in memory that holds one value. The value can change while the program runs.
The name is called an identifier. Cambridge pseudocode writes identifiers in PascalCase, such as `TotalScore`.
`DECLARE` gives the name and the data type before the variable is used.
The arrow `β` means assignment: work out the value on the right, then store it in the variable on the left.
e.g.ExampleScore β 0 stores 0.
Score β Score + 5 reads the old value (0), adds 5, and stores 5.
Output: 5
DECLARE Score : INTEGER
Score β 0
Score β Score + 5
OUTPUT Score
score = 0
score = score + 5
print(score)
?Why?Python does not need a declaration. It works out the type from the value. Cambridge pseudocode declares every variable so the type is clear to the reader.
!Watch outRead `Score β Score + 5` from right to left. It is not a maths equation. It means: work out Score + 5, then put the answer back in Score.
Constants: values that never change
A constant is a named value that is set once. It cannot change while the program runs.
In pseudocode write `CONSTANT`, the name, `β` and the value. No data type is given: the value shows it.
Python has no true constants. Programmers write the name in CAPITALS to mean: do not change this.
e.g.ExampleSpain's standard VAT (IVA) is 21%, so the rate is 0.21.
50.0 Γ (1 + 0.21) = 50.0 Γ 1.21 = 60.5
Output: Price with VAT: 60.5
CONSTANT VATRate β 0.21
DECLARE Price : REAL
Price β 50.0
OUTPUT "Price with VAT: ", Price * (1 + VATRate)
VAT_RATE = 0.21
price = 50.0
print("Price with VAT:", price * (1 + VAT_RATE))?Why?If the VAT rate changes, you edit one line instead of every line that uses 0.21. The name also tells the reader what 0.21 means. The program cannot change it by mistake.
!Watch outUse a constant only for a value that is fixed for the whole run, like a tax rate or the size of an array. A value that the program updates, like a score, must be a variable.
The five data types
A data type says what kind of value a variable holds. It decides how the value is stored and what you can do with it.
Cambridge uses five data types. A CHAR goes in single quotes. A STRING goes in double quotes.
DECLARE Age : INTEGER
DECLARE Height : REAL
DECLARE Grade : CHAR
DECLARE FirstName : STRING
DECLARE IsMember : BOOLEAN
Age β 15
Height β 1.68
Grade β 'A'
FirstName β "Lucia"
IsMember β TRUE
age = 15
height = 1.68
grade = "A"
first_name = "Lucia"
is_member = True
print(type(age), type(height), type(grade), type(first_name), type(is_member))
?Why?The type decides which operations make sense. You can add two INTEGERs. You cannot multiply two names.
Choosing the right data type
Ask two questions. Will I do maths with it? Can it have a decimal part?
A phone number or a postcode is a STRING. You never add phone numbers, and an INTEGER would lose a leading 0.
Use BOOLEAN for anything with only two states: paid or not paid, logged in or not.
!Watch outDo not store a phone number as INTEGER. 0034 912 345 678 would lose its zeros and spaces. Exam answers need a reason: STRING, because it can start with 0 and no calculations are done on it.
Input and output
Input is data going into the program, usually typed by the user. `INPUT Name` waits and stores what is typed in Name.
Output is data coming out, usually on screen. `OUTPUT` can show text and variables separated by commas.
Always show a message before an INPUT so the user knows what to type. This message is a prompt.
In Python, `input()` always gives a string. Wrap it in `int()` or `float()` to get a number.
e.g.ExampleThe user types Lucia, then 15.
Age + 1 = 15 + 1 = 16
Output: Hello Lucia, next year you will be 16
DECLARE Name : STRING
DECLARE Age : INTEGER
OUTPUT "Enter your name"
INPUT Name
OUTPUT "Enter your age"
INPUT Age
OUTPUT "Hello ", Name, ", next year you will be ", Age + 1
name = input("Enter your name: ")
age = int(input("Enter your age: "))
print("Hello " + name + ", next year you will be", age + 1)!Watch outForgetting `int()` is the most common Python bug here. Without it, age holds the text "15". Then `age + 1` crashes, because Python cannot add text and a number.
Sequence: one step after another
Sequence means the statements run one after another, in the order they are written.
The order matters. If a value is used before it is worked out, the answer is wrong.
e.g.ExampleThree cinema tickets at 7.50 euros each.
Total = 3 Γ 7.50 = 22.50
Output: Total to pay: 22.5
CONSTANT TicketPrice β 7.50
DECLARE Tickets : INTEGER
DECLARE Total : REAL
Tickets β 3
Total β Tickets * TicketPrice
OUTPUT "Total to pay: ", Total
TICKET_PRICE = 7.50
tickets = 3
total = tickets * TICKET_PRICE
print("Total to pay:", total)!Watch outSwap the last two lines and the program outputs Total before it has a value. Exam questions often ask you to find statements in the wrong order.
Selection with IF
Selection means the program chooses which statements to run, using a condition.
A condition is a question with a TRUE or FALSE answer, such as `Mark >= 50`.
The THEN part runs when the condition is TRUE. The ELSE part runs when it is FALSE. ELSE is optional. ENDIF closes the IF.
e.g.ExampleMark = 62. Is 62 >= 50? TRUE, so the output is Pass.
Mark = 49. Is 49 >= 50? FALSE, so the output is Fail.
DECLARE Mark : INTEGER
OUTPUT "Enter the mark"
INPUT Mark
IF Mark >= 50
THEN
OUTPUT "Pass"
ELSE
OUTPUT "Fail"
ENDIFmark = int(input("Enter the mark: "))
if mark >= 50:
print("Pass")
else:
print("Fail")?Why?Python uses a colon and indentation to show which lines belong to the IF. Pseudocode uses THEN, ELSE and ENDIF. Both mean the same thing.
Nested IF: up to three levels
A nested IF is an IF inside another IF. Use it when the next question depends on the first answer.
Cambridge questions use nesting up to three levels deep. More than that is hard to read.
In pseudocode the next IF goes inside the ELSE. Python can shorten ELSE followed by IF to `elif`.
e.g.ExampleMark = 58.
Level 1: is 58 >= 70? FALSE, so go to ELSE.
Level 2: is 58 >= 55? TRUE, so output Grade B.
Level 3 is never checked.
Output: Grade B
DECLARE Mark : INTEGER
Mark β 58
IF Mark >= 70
THEN
OUTPUT "Grade A"
ELSE
IF Mark >= 55
THEN
OUTPUT "Grade B"
ELSE
IF Mark >= 40
THEN
OUTPUT "Grade C"
ELSE
OUTPUT "Ungraded"
ENDIF
ENDIF
ENDIFmark = 58
if mark >= 70:
print("Grade A")
elif mark >= 55:
print("Grade B")
elif mark >= 40:
print("Grade C")
else:
print("Ungraded")!Watch outTest the highest boundary first. If you test `Mark >= 40` first, a mark of 85 outputs Grade C and stops. Every IF needs its own ENDIF.
Selection with CASE
`CASE OF` picks one path from many, using the value of one variable.
Each line has a value, a colon, then the statement to run. `OTHERWISE` catches every value that is not listed. ENDCASE closes it.
CASE is neater than a long chain of IFs when one variable is compared with fixed values.
Python 3.10 and later has `match` and `case`. `case _` works like OTHERWISE. Older Python uses if, elif and else.
e.g.ExampleThe user types S.
'A'? No. 'S'? Yes, so output Subtracting and leave the CASE.
The user types X: no value matches, so OTHERWISE outputs Unknown choice.
DECLARE Choice : CHAR
OUTPUT "A = add, S = subtract, Q = quit"
INPUT Choice
CASE OF Choice
'A' : OUTPUT "Adding"
'S' : OUTPUT "Subtracting"
'Q' : OUTPUT "Goodbye"
OTHERWISE : OUTPUT "Unknown choice"
ENDCASE
choice = input("A = add, S = subtract, Q = quit: ")
match choice:
case "A":
print("Adding")
case "S":
print("Subtracting")
case "Q":
print("Goodbye")
case _:
print("Unknown choice")!Watch outCASE compares one variable with exact values. For a condition that joins two tests, like `Mark >= 50 AND Attendance > 90`, use IF.
Relational and logical operators
Relational operators compare two values. The answer is always TRUE or FALSE.
Logical operators join conditions. `AND` needs both to be TRUE. `OR` needs at least one TRUE. `NOT` swaps TRUE and FALSE.
The table uses Age = 15.
e.g.ExampleA metro discount is for under-26s or over-65s who have a travel card.
Age < 26 β TRUE. Age >= 65 β FALSE. TRUE OR FALSE β TRUE.
HasCard = TRUE β TRUE. TRUE AND TRUE β TRUE.
Output: Discount fare
DECLARE Age : INTEGER
DECLARE HasCard : BOOLEAN
Age β 15
HasCard β TRUE
IF (Age < 26 OR Age >= 65) AND HasCard = TRUE
THEN
OUTPUT "Discount fare"
ELSE
OUTPUT "Full fare"
ENDIFage = 15
has_card = True
if (age < 26 or age >= 65) and has_card == True:
print("Discount fare")
else:
print("Full fare")!Watch outIn pseudocode `=` compares. In Python `=` stores a value and `==` compares. `if age = 15:` is a syntax error in Python. Use brackets when you mix AND and OR, so the order is clear.
Arithmetic operators, DIV and MOD
Cambridge uses seven arithmetic operators: `+`, `-`, `*`, `/`, `^`, `DIV` and `MOD`.
`/` gives the full answer, which can have a decimal part. `DIV` gives only the whole-number part. `MOD` gives the remainder.
You may see `DIV(17, 5)` or `17 DIV 5`. Both mean the same.
Try the toy: share 17 sweets between 5 friends. Each friend gets DIV(17, 5) = 3. MOD(17, 5) = 2 sweets are left over.
e.g.ExampleA film lasts 135 minutes.
DIV(135, 60) = 2, because 60 fits into 135 two whole times.
MOD(135, 60) = 135 - (2 Γ 60) = 135 - 120 = 15
Output: 2 hours and 15 minutes
DECLARE Minutes : INTEGER
Minutes β 135
OUTPUT DIV(Minutes, 60), " hours and ", MOD(Minutes, 60), " minutes"
minutes = 135
print(minutes // 60, "hours and", minutes % 60, "minutes")
?Why?MOD is very useful. `MOD(Number, 2) = 0` is TRUE when a number is even. `MOD(Number, 10)` gives the last digit, as used in check digits.
!Watch outIn Python `^` does something else, so use `**` for power. Also, Python `/` always gives a REAL: `6 / 2` gives `3.0`.
There is something to try for this step in the IGCSE library.
Iteration: the count-controlled FOR loop
Iteration means repeating a block of statements. A block that repeats is called a loop.
A count-controlled loop repeats a set number of times. Cambridge writes it `FOR β¦ TO β¦ NEXT`.
The loop variable counts for you. `STEP` sets how much it goes up, or down, each time.
e.g.ExampleFirst loop: Count takes 1, 2, 3, 4, 5.
Output: 3, 6, 9, 12, 15 (one per line)
Second loop: Count goes 10, 8, 6, 4, 2, 0.
DECLARE Count : INTEGER
FOR Count β 1 TO 5
OUTPUT Count * 3
NEXT Count
FOR Count β 10 TO 0 STEP -2
OUTPUT Count
NEXT Count
for count in range(1, 6):
print(count * 3)
for count in range(10, -1, -2):
print(count)!Watch outPython `range` stops before its end value. `FOR Count β 1 TO 5` becomes `range(1, 6)`. Counting down to 0 becomes `range(10, -1, -2)`.
The pre-condition WHILE loop
A pre-condition loop checks its condition before each pass. Cambridge writes it `WHILE β¦ DO β¦ ENDWHILE`.
It repeats while the condition is TRUE. If the condition is FALSE at the start, the loop body never runs.
Use it when you do not know how many passes are needed.
e.g.Example1000 euros grows by 10% a year. When does it reach 1500?
1000 < 1500 TRUE β 1100, Years 1
1100 < 1500 TRUE β 1210, Years 2
1210 < 1500 TRUE β 1331, Years 3
1331 < 1500 TRUE β 1464.10, Years 4
1464.10 < 1500 TRUE β 1610.51, Years 5
1610.51 < 1500 FALSE β stop
Output: Years needed: 5
DECLARE Savings : REAL
DECLARE Years : INTEGER
Savings β 1000.0
Years β 0
WHILE Savings < 1500 DO
Savings β Savings * 1.1
Years β Years + 1
ENDWHILE
OUTPUT "Years needed: ", Years
savings = 1000.0
years = 0
while savings < 1500:
savings = savings * 1.1
years = years + 1
print("Years needed:", years)!Watch outSomething inside the loop must change the condition. If Savings never changed, the loop would never stop. This is an infinite loop.
The post-condition REPEAT UNTIL loop
A post-condition loop checks its condition after each pass. Cambridge writes it `REPEAT β¦ UNTIL`.
The body always runs at least once. The loop stops when the condition becomes TRUE.
It suits validation: ask for the input, and ask again until it is acceptable.
Python has no REPEAT UNTIL. Use `while True:` and `break` out of the loop when the stop condition is TRUE.
e.g.ExampleThe user types 150: condition FALSE, so repeat.
The user types -3: FALSE, so repeat.
The user types 72: TRUE, so stop.
Output: Accepted: 72
DECLARE Mark : INTEGER
REPEAT
OUTPUT "Enter a mark from 0 to 100"
INPUT Mark
UNTIL Mark >= 0 AND Mark <= 100
OUTPUT "Accepted: ", Mark
while True:
mark = int(input("Enter a mark from 0 to 100: "))
if mark >= 0 and mark <= 100:
break
print("Accepted:", mark)!Watch outWHILE keeps going while its condition is TRUE. UNTIL stops when its condition is TRUE. So the conditions are opposites. `WHILE Mark < 0 OR Mark > 100` matches `UNTIL Mark >= 0 AND Mark <= 100`.
Choosing the right loop
First ask: do I know how many times? If yes, use FOR.
If not, ask: must it run at least once? If yes, use REPEAT UNTIL. If it might need to run zero times, use WHILE.
!Watch outIf a question says 'use a pre-condition loop', you must use WHILE. Using a different loop loses marks, even if the program works.
Totalling and counting
Totalling keeps a running total: `Total β Total + Value`.
Counting adds 1 each time something happens: `Count β Count + 1`.
Set both to 0 before the loop starts.
e.g.ExampleMarks typed: 45, 72, 60, 38, 90
Total = 45 + 72 + 60 + 38 + 90 = 305
Average = 305 / 5 = 61 (Python shows 61.0)
Passes (50 or more): 72, 60, 90, so PassCount = 3
DECLARE Total : INTEGER
DECLARE PassCount : INTEGER
DECLARE Mark : INTEGER
DECLARE Count : INTEGER
Total β 0
PassCount β 0
FOR Count β 1 TO 5
OUTPUT "Enter mark"
INPUT Mark
Total β Total + Mark
IF Mark >= 50
THEN
PassCount β PassCount + 1
ENDIF
NEXT Count
OUTPUT "Total: ", Total
OUTPUT "Average: ", Total / 5
OUTPUT "Passes: ", PassCounttotal = 0
pass_count = 0
for count in range(1, 6):
mark = int(input("Enter mark: "))
total = total + mark
if mark >= 50:
pass_count = pass_count + 1
print("Total:", total)
print("Average:", total / 5)
print("Passes:", pass_count)!Watch outIf `Total β 0` is inside the loop, it resets on every pass. The final total is then only the last mark.
String handling: LENGTH, UCASE, LCASE
A string is a sequence of characters. Each character has a position number.
`LENGTH(s)` gives the number of characters, and spaces count.
`UCASE(s)` gives the string in capitals. `LCASE(s)` gives it in lower case. The variable itself only changes if you assign the result back.
e.g.Example"Madrid Spain" has 6 letters + 1 space + 5 letters = 12 characters.
Output:
12
MADRID SPAIN
madrid spain
DECLARE City : STRING
City β "Madrid Spain"
OUTPUT LENGTH(City)
OUTPUT UCASE(City)
OUTPUT LCASE(City)
city = "Madrid Spain"
print(len(city))
print(city.upper())
print(city.lower())
?Why?UCASE and LCASE make comparisons fair. A user may type yes, YES or Yes. `IF UCASE(Answer) = "YES"` accepts all three.
SUBSTRING and the first position: 1 or 0
`SUBSTRING(s, start, length)` takes a piece out of a string. You give the start position and how many characters you want.
In Cambridge pseudocode the first character is position 1. In Python the first character is position 0.
Python uses slicing: `s[start:end]` takes characters from start up to, but not including, end.
Try the toy: type MADRID as the string. Set the start to 4 and the length to 3, and check you get RID. Then try LENGTH, UCASE and LCASE on the same string.
e.g.ExampleSUBSTRING("MADRID", 4, 3): start at position 4 (R) and take 3 characters β RID.
Python: start = 4 - 1 = 3. End = 3 + 3 = 6. word[3:6] β "RID".
Rule: Python start = pseudocode start - 1. Python end = Python start + length.
DECLARE Word : STRING
Word β "MADRID"
OUTPUT SUBSTRING(Word, 1, 3)
OUTPUT SUBSTRING(Word, 4, 3)
OUTPUT SUBSTRING(Word, 1, 1)
word = "MADRID"
print(word[0:3])
print(word[3:6])
print(word[0])
!Watch outThe exam says whether the first character is 0 or 1, so read the question. The third value in SUBSTRING is a length, not an end position.
There is something to try for this step in the IGCSE library.
Procedures and parameters
A subroutine is a named block of code that does one job. You write it once and call it whenever you need it.
A procedure is a subroutine that does a task but does not give a value back. You run it with `CALL`.
A parameter is a variable in the heading that receives a value when the subroutine is called. Cambridge uses up to three.
The value you pass in is called the argument. Here "Ana" and 2 are the arguments.
e.g.ExampleCALL Greet("Ana", 2) puts "Ana" in Name and 2 in Times.
The loop runs 2 times.
Output:
Hello Ana
Hello Ana
PROCEDURE Greet(Name : STRING, Times : INTEGER)
DECLARE Count : INTEGER
FOR Count β 1 TO Times
OUTPUT "Hello ", Name
NEXT Count
ENDPROCEDURE
CALL Greet("Ana", 2)def greet(name, times):
for count in range(1, times + 1):
print("Hello", name)
greet("Ana", 2)?Why?Subroutines stop you repeating code. The program is shorter, each part can be tested on its own, and a fix is made in one place.
Functions: subroutines that return a value
A function is a subroutine that returns a value to the place where it was called.
The heading gives the type of the value it returns, such as `RETURNS REAL`. `RETURN` sends the value back.
A function gives a value, so you use it inside an expression or an OUTPUT. You do not use CALL.
e.g.ExampleAverage(70, 64, 85)
(70 + 64 + 85) / 3 = 219 / 3 = 73
The function returns 73, which is stored in Result.
Output: Average: 73 (Python shows 73.0)
FUNCTION Average(Mark1 : REAL, Mark2 : REAL, Mark3 : REAL) RETURNS REAL
RETURN (Mark1 + Mark2 + Mark3) / 3
ENDFUNCTION
DECLARE Result : REAL
Result β Average(70, 64, 85)
OUTPUT "Average: ", Result
def average(mark1, mark2, mark3):
return (mark1 + mark2 + mark3) / 3
result = average(70, 64, 85)
print("Average:", result)!Watch outA function must RETURN a value of the type in its heading. Writing CALL before a function, or RETURN inside a procedure, loses marks.
Local and global variables
Scope means the part of the program where a variable can be used.
A global variable is declared in the main program. Every part of the program can use it.
A local variable is declared inside a subroutine. It exists only while that subroutine runs, and nothing outside can see it.
In Python a function can read a global variable. To change it, the function must first say `global`.
e.g.ExampleBonus = 5, so Doubled = 5 Γ 2 = 10.
Score = 0 + 10 = 10.
Output: 10
OUTPUT Doubled in the main program would be an error: Doubled no longer exists.
DECLARE Score : INTEGER // global
Score β 0
PROCEDURE AddBonus(Bonus : INTEGER)
DECLARE Doubled : INTEGER // local
Doubled β Bonus * 2
Score β Score + Doubled
ENDPROCEDURE
CALL AddBonus(5)
OUTPUT Score
score = 0 # global
def add_bonus(bonus):
global score
doubled = bonus * 2 # local
score = score + doubled
add_bonus(5)
print(score)?Why?Local variables keep each subroutine separate. Two subroutines can both use a variable called Count without clashing. The memory is freed when the subroutine ends.
!Watch outToo many global variables make bugs hard to find, because any line could change them. Pass values in as parameters and return results instead.
Library routines: MOD, DIV, ROUND, RANDOM
A library routine is a ready-made, tested subroutine that comes with the language. You use it without writing it.
Cambridge expects four: `MOD`, `DIV`, `ROUND` and `RANDOM`. MOD and DIV were in the arithmetic step.
`ROUND(Value, Places)` rounds to a number of decimal places. `ROUND(6.97354, 2)` gives 6.97.
`RANDOM()` gives a random REAL number from 0 to 1. Multiply it and round it to get the range you want.
e.g.ExampleROUND(19.987, 2) = 19.99
Say RANDOM() gives 0.62.
0.62 Γ 5 = 3.1. ROUND(3.1, 0) = 3. 3 + 1 = 4.
Output: You rolled 4
RANDOM() Γ 5 is from 0 to 5, so Dice is always from 1 to 6.
DECLARE Price : REAL
DECLARE Dice : INTEGER
Price β 19.987
OUTPUT ROUND(Price, 2)
Dice β ROUND(RANDOM() * 5, 0) + 1
OUTPUT "You rolled ", Dice
import random
price = 19.987
print(round(price, 2))
dice = random.randint(1, 6)
print("You rolled", dice)?Why?Library routines save time. They are already tested, so they are reliable.
!Watch outPython's `round()` sends an exact half to the nearest even number: `round(2.5)` gives 2 and `round(3.5)` gives 4. Cambridge pseudocode questions expect normal rounding, where 2.5 becomes 3.
Writing maintainable programs
A maintainable program is easy for another programmer, or you months later, to read, fix and update.
Use meaningful identifiers: `TotalPrice`, not `tp` or `x`.
Add comments that explain what a part does and why. Pseudocode comments start with `//`. Python comments start with `#`.
Use procedures and functions so each job lives in one named place. Use constants for fixed values, and indent code inside IFs, loops and subroutines.
e.g.ExampleHard to maintain:
x β y / 30 + 8.5
Maintainable (above):
600 / 30 = 20. 20 + 8.5 = 28.5
Output: Cost per pupil: 28.5
// Works out the cost of a school trip for one pupil
CONSTANT CoachCost β 600.0
CONSTANT EntryFee β 8.5
FUNCTION CostPerPupil(Pupils : INTEGER) RETURNS REAL
// the coach is shared, the entry fee is paid by each pupil
RETURN CoachCost / Pupils + EntryFee
ENDFUNCTION
OUTPUT "Cost per pupil: ", CostPerPupil(30)
# Works out the cost of a school trip for one pupil
COACH_COST = 600.0
ENTRY_FEE = 8.5
def cost_per_pupil(pupils):
# the coach is shared, the entry fee is paid by each pupil
return COACH_COST / pupils + ENTRY_FEE
print("Cost per pupil:", cost_per_pupil(30))?Why?Real programs are changed for years by many people. Clear code is cheaper to fix and less likely to get new bugs.