An original Thinka practice paper modelled on the structure and difficulty of the Jun 2023 Cambridge International A Level Computer Science paper. Not affiliated with or reproduced from Cambridge.
Paper 1: Principles of Computer Science
Answer all questions. Write your answers in the spaces provided. No calculators allowed.
6 Question · 79.98 marks
Question 1 · multiple-choice
13.33 marks
An 8-bit register contains the binary pattern representing a signed integer in two's complement form: 10110100. The computer performs an arithmetic shift right by 2 places, followed by a logical bitwise OR with the binary mask 00001111. What is the resulting decimal value of this 8-bit register after these operations?
A.-17
B.-19
C.-76
D.-113
Show answer & marking schemeHide answer & marking scheme
Worked solution
First, the initial register pattern 10110100 represents a signed negative number. Performing an arithmetic shift right by 1 place gives 11011010 (preserving the sign bit). Shifting right by a second place gives 11101101. Next, we apply the logical bitwise OR with 00001111: (11101101 OR 00001111) which results in 11101111. To convert the final two's complement binary number 11101111 back to decimal, we invert the bits to get 00010000, and add 1 to get 00010001, which is 17 in denary. Since the original sign bit was negative, the result is -17.
Marking scheme
1. Correct arithmetic shift right by 2 places to produce 11101101 (4 marks). 2. Correct application of logical bitwise OR with 00001111 to produce 11101111 (4 marks). 3. Correct conversion of two's complement binary to decimal value of -17 (5.33 marks).
Question 2 · multiple-choice
13.33 marks
An organization uses asymmetric encryption to secure communication between a client and a server. The client wants to send a confidential message to the server, and also wants to ensure non-repudiation. Which combination of keys must be used to encrypt the message body for confidentiality, and to sign the message for non-repudiation?
A.Message encrypted with Client's Private Key; Signed with Server's Public Key
B.Message encrypted with Server's Public Key; Signed with Client's Private Key
C.Message encrypted with Client's Public Key; Signed with Server's Private Key
D.Message encrypted with Server's Private Key; Signed with Client's Public Key
Show answer & marking schemeHide answer & marking scheme
Worked solution
To achieve confidentiality, only the receiver (the server) must be able to decrypt the message. This requires the sender to encrypt the message using the Server's Public Key, since only the corresponding Server's Private Key can decrypt it. To achieve non-repudiation, the sender must sign the message using their own Client's Private Key. The receiver (and others) can then verify the signature using the Client's Public Key, proving the message originated from the client.
Marking scheme
1. Identification of the Server's Public Key for message encryption to maintain confidentiality (6 marks). 2. Identification of the Client's Private Key for digital signature to ensure non-repudiation (6 marks). 3. Selecting the correct combined option B (1.33 marks).
Question 3 · multiple-choice
13.33 marks
A network administrator is configuring a Local Area Network (LAN) using a star topology. The administrator wants to minimize unnecessary network traffic and maximize security by directing data packets only to their intended destination devices. Which network hardware device should be used as the central node of the star topology, and what addressing scheme does it primarily use to route these data frames locally?
A.Router, using IP addresses
B.Hub, using MAC addresses
C.Switch, using MAC addresses
D.Switch, using IP addresses
Show answer & marking schemeHide answer & marking scheme
Worked solution
A network switch is the ideal central node for a star topology LAN when the goal is to direct traffic only to the specific destination device. Unlike a hub which broadcasts data to all ports, a switch inspects the destination MAC (Media Access Control) address of incoming frames and forwards them only to the port connected to the recipient device. Routers are used to route traffic between different networks using IP addresses, rather than locally forwarding frames within a single LAN star topology.
Marking scheme
1. Correct choice of Switch as the central node to reduce collisions and unnecessary traffic (6 marks). 2. Correct identification of MAC address as the addressing protocol used at the Data Link layer for local frame forwarding (6 marks). 3. Selection of correct option C (1.33 marks).
Question 4 · multiple-choice
13.33 marks
Consider the Boolean expression: \(Q = \overline{(A \cdot B)} + (B \cdot \overline{C})\). If the input values are \(A = 1\), \(B = 1\), and \(C = 0\), what is the evaluated output value of \(Q\), and which single logic gate represents the sub-expression \(\overline{(A \cdot B)}\)?
A.\(Q = 0\), replaced by an AND gate
B.\(Q = 1\), replaced by a NAND gate
C.\(Q = 0\), replaced by a NOR gate
D.\(Q = 1\), replaced by an OR gate
Show answer & marking schemeHide answer & marking scheme
Worked solution
We evaluate the expression step-by-step. First, for the sub-expression \(\overline{(A \cdot B)}\), substituting \(A=1\) and \(B=1\) gives \(\overline{(1 \cdot 1)} = \overline{1} = 0\). The gate representing \(\overline{(A \cdot B)}\) is a NAND gate. Next, for the sub-expression \((B \cdot \overline{C})\), substituting \(B=1\) and \(C=0\) gives \((1 \cdot \overline{0}) = 1 \cdot 1 = 1\). Finally, we combine the terms using the OR operator: \(Q = 0 + 1 = 1\). Thus, the output is 1 and the sub-expression is a NAND gate.
Marking scheme
1. Evaluation of the left sub-expression to 0 (4 marks). 2. Evaluation of the right sub-expression to 1 (4 marks). 3. Combining terms to find logical output Q = 1 (3 marks). 4. Identifying the sub-expression as equivalent to a NAND gate (2.33 marks).
Question 5 · multiple-choice
13.33 marks
A student wants to compress high-fidelity audio recordings to play them on a portable device with limited storage. They can use either lossy MP3 compression or lossless FLAC compression. Which statement correctly describes the key differences and trade-offs between these two compression methods?
A.FLAC will result in a smaller file size than MP3, but will permanently discard high-frequency sounds that the human ear cannot easily detect
B.MP3 will result in a larger file size than FLAC, but preserves the original data perfectly so it can be decompressed back into the exact original file
C.MP3 will result in a smaller file size than FLAC by permanently discarding audio data, while FLAC reduces file size without losing any original data
D.Both MP3 and FLAC are lossy compression methods, but MP3 is designed for voice and FLAC is designed specifically for instrumental music
Show answer & marking schemeHide answer & marking scheme
Worked solution
MP3 is a lossy compression format, which means it permanently removes audio data that is less noticeable to the human ear (such as very high frequencies or quiet sounds masked by louder sounds) in order to achieve a highly reduced file size. FLAC is a lossless compression format, meaning it reduces the file size without removing any audio data, allowing the exact original recording to be reconstructed, though the resulting files are larger than those compressed with MP3.
Marking scheme
1. Explanation of lossy compression (MP3) reducing size by permanently removing data (5 marks). 2. Explanation of lossless compression (FLAC) maintaining original data integrity (5 marks). 3. Identifying the correct trade-off where MP3 results in smaller files than FLAC (3.33 marks).
Question 6 · multiple-choice
13.33 marks
When multiple programs run simultaneously, the physical RAM can become fully occupied. To prevent the system from running out of memory, the operating system uses virtual memory. Which statement best describes how virtual memory functions in this situation?
A.The operating system compresses data currently in RAM to double the available physical capacity
B.The operating system temporarily transfers inactive pages of data from RAM to a secondary storage device
C.The operating system increases the clock speed of the CPU to process data faster, clearing physical memory quicker
D.The operating system terminates background processes automatically to free up RAM for the active window
Show answer & marking schemeHide answer & marking scheme
Worked solution
Virtual memory is a memory management technique where the operating system uses secondary storage (such as a hard disk drive or SSD) to act as an extension of the primary physical RAM. When physical RAM is full, the operating system moves inactive pages or blocks of data from RAM into a designated space on the secondary storage device. This frees up RAM space for active processes. When the swapped-out data is needed again, it is loaded back into RAM, swapping out other inactive pages if necessary.
Marking scheme
1. Identifying that secondary storage is used as an extension of physical RAM (5 marks). 2. Describing the process of transferring inactive pages of memory to secondary storage to free up RAM (5 marks). 3. Correct selection of option B (3.33 marks).
Paper 2: Application of Computational Thinking
Carry out practical tasks on the computer system and save new or amended code. Use only Python, C#, or Java.
6 Question · 79.98 marks
Question 1 · multiple-choice
13.33 marks
An offline database contains a list of temperatures recorded at meteorological stations. A programmer is developing a Python subprogram `find_last_cold_day(temperatures, threshold)` that searches an array of numbers and returns the index of the last occurrence of a temperature that is strictly below the given `threshold`. If no such temperature is found, the subprogram must return `-1`.
For example: `find_last_cold_day([12, 4, 8, 3, 15, 2], 5)` should return `5` (the index of the element `2`, which is the last value below `5`).
Which of the following Python implementations correctly and efficiently meets these requirements?
A.def find_last_cold_day(temperatures, threshold): for i in range(len(temperatures) - 1, -1, -1): if temperatures[i] < threshold: return i return -1
B.def find_last_cold_day(temperatures, threshold): last_idx = -1 for i in range(len(temperatures)): if temperatures[i] <= threshold: last_idx = i return last_idx
C.def find_last_cold_day(temperatures, threshold): for i in range(len(temperatures), 0, -1): if temperatures[i] < threshold: return i return -1
D.def find_last_cold_day(temperatures, threshold): index = -1 for i in range(len(temperatures) - 1, 0, -1): if temperatures[i] < threshold: index = i return index
Show answer & marking schemeHide answer & marking scheme
Worked solution
Option A is correct because it starts the loop iteration at the last index of the list (`len(temperatures) - 1`) and moves backwards to index `0` (step `-1`). Since it goes backwards, the first matching element it encounters is guaranteed to be the last occurrence in the original list. It returns the index `i` immediately, preventing unnecessary further iterations. If the loop completes without finding a match, it returns `-1`.
Marking scheme
Loop design (4 marks): Traverses the list backwards using range starting at len(temperatures)-1 down to -1 with step -1. Selection condition (4 marks): Tests if the temperature is strictly less than the threshold (uses < instead of <=). Immediate termination (3 marks): Returns index 'i' immediately upon finding the first match when traversing backwards. Default return value (2.33 marks): Returns -1 only after the loop terminates without finding any match.
Question 2 · multiple-choice
13.33 marks
Consider the following pseudo-algorithm designed to perform a bubble sort on an array of integers `arr` containing `N` elements:
```text SET outer TO 0 SET swapped TO True WHILE outer < N - 1 AND swapped IS True SET swapped TO False FOR inner FROM 0 TO N - outer - 2 IF arr[inner] > arr[inner + 1] THEN TEMP = arr[inner] arr[inner] = arr[inner + 1] arr[inner + 1] = TEMP SET swapped TO True ENDIF ENDFOR SET outer TO outer + 1 ENDWHILE ```
If the input array is `arr = [5, 1, 4, 2]`, complete a dry run to determine the state of the array after the FIRST full pass of the inner loop (when `outer` has completed its first iteration, i.e., `outer` is about to increment to `1`).
Choose the option that represents the state of `arr` and the value of `swapped` at this exact point.
A.arr = [1, 4, 2, 5] and swapped = True
B.arr = [1, 5, 2, 4] and swapped = True
C.arr = [1, 4, 2, 5] and swapped = False
D.arr = [1, 2, 4, 5] and swapped = True
Show answer & marking schemeHide answer & marking scheme
Worked solution
Option A is correct. Let's trace the execution for N=4: - Initially, outer = 0, swapped = True. - Inside the loop, swapped is set to False. - The inner loop runs for inner from 0 to 4 - 0 - 2 = 2: - inner = 0: arr[0] (5) > arr[1] (1) is True. Swap: arr becomes [1, 5, 4, 2], swapped becomes True. - inner = 1: arr[1] (5) > arr[2] (4) is True. Swap: arr becomes [1, 4, 5, 2], swapped is set to True. - inner = 2: arr[2] (5) > arr[3] (2) is True. Swap: arr becomes [1, 4, 2, 5], swapped is set to True. - At the end of this pass, arr is [1, 4, 2, 5] and swapped is True. Then, outer is incremented to 1.
Marking scheme
Tracing first swap (4 marks): Correctly swap 5 and 1 to obtain [1, 5, 4, 2]. Tracing subsequent swaps (4 marks): Correctly swap 5 and 4, then 5 and 2, to obtain final state [1, 4, 2, 5]. Tracking variable states (3 marks): Correctly verify that swapped is True at the end of the pass. Correct overall output (2.33 marks): Identify the exact state matching Option A.
Question 3 · multiple-choice
13.33 marks
A developer is implementing a function in Python that checks whether a given positive integer `num` is a prime number. They decide to use a helper variable `is_prime` as a boolean flag.
Here is the incomplete Python code:
```python def check_prime(num): if num <= 1: return False
is_prime = True # for i in range(2, limit): # is_prime = False break
return is_prime ```
To make this code run as efficiently as possible while still being mathematically correct, which of the following choices should replace `` and ``?
A.: limit = int(num ** 0.5) + 1 : if num % i == 0:
B.: limit = num // 2 : if num / i == 0:
C.: limit = int(num ** 0.5) : if num % i == 0:
D.: limit = num : if num % i != 0:
Show answer & marking schemeHide answer & marking scheme
Worked solution
To check if a number is prime, we only need to test for factors up to its square root (inclusive). The square root of `num` is computed as `num ** 0.5`. In Python, the range function `range(start, stop)` is exclusive of the `stop` boundary. Therefore, we must convert the square root to an integer and add `1` to ensure the square root itself is tested if it is an integer. This gives `limit = int(num ** 0.5) + 1` for . Inside the loop, must check if `num` is divisible by `i` using the modulo operator: `if num % i == 0:`.
Marking scheme
Square root limit efficiency (4 marks): Correctly identify that factors only need to be tested up to the square root of num. Range boundary handling (4 marks): Identify that int(num ** 0.5) + 1 is required to include the square root in the range function. Modulo syntax (3 marks): Use % i == 0 to check for divisibility rather than float division /. Overall correctness (2.33 marks): Choose Option A which contains both correct lines.
Question 4 · multiple-choice
13.33 marks
A student is creating a subprogram in Python to perform a Caesar cipher encryption on a string containing ONLY uppercase alphabetical characters (A-Z). The shift value `k` can be any positive integer (including values larger than 26).
The ASCII value of 'A' is 65, and 'Z' is 90.
Here is the incomplete Python code:
```python def encrypt_caesar(plain_text, k): cipher_text = "" for char in plain_text: # Convert character to a 0-25 scale original_val = ord(char) - 65 # Apply shift and wrap around # # Convert back to character and append cipher_text += chr(new_val + 65) return cipher_text ```
Which of the following single-line code blocks should replace `` to correctly calculate `new_val`?
A.new_val = (original_val + k) % 26
B.new_val = (original_val + k % 26) - 65
C.new_val = (original_val + k) // 26
D.new_val = (original_val + 26) % k
Show answer & marking schemeHide answer & marking scheme
Worked solution
The character has been scaled to the range 0-25. To perform the Caesar cipher shift, we add the shift value `k` to `original_val` and then apply modulo 26 (`% 26`) to wrap any overflow back into the 0-25 range. This correctly handles any positive integer `k` (including those greater than 26). Thus, `new_val = (original_val + k) % 26` is correct.
Marking scheme
Modulo arithmetic (4 marks): Correctly identify that % 26 is required to wrap values exceeding the alphabet size. Shift variable utilization (4 marks): Correctly add 'k' to 'original_val'. Syntactical alignment (3 marks): Match the 0-25 relative offset format. Selection of correct option (2.33 marks): Identify Option A as the correct line of code.
Question 5 · multiple-choice
13.33 marks
A program stores an image as a 2D list (grid) of dimensions N x N, representing pixel color values. The programmer wants to write a function `rotate_90_clockwise(grid)` that returns a new 2D list representing the image rotated 90 degrees clockwise.
Which of the following Python functions correctly implements this 90-degree clockwise rotation?
A.def rotate_90_clockwise(grid): n = len(grid) new_grid = [[0] * n for _ in range(n)] for r in range(n): for c in range(n): new_grid[c][n - 1 - r] = grid[r][c] return new_grid
B.def rotate_90_clockwise(grid): n = len(grid) new_grid = [[0] * n for _ in range(n)] for r in range(n): for c in range(n): new_grid[n - 1 - r][c] = grid[r][c] return new_grid
C.def rotate_90_clockwise(grid): n = len(grid) new_grid = [[0] * n for _ in range(n)] for r in range(n): for c in range(n): new_grid[r][c] = grid[n - 1 - c][r] return new_grid
D.def rotate_90_clockwise(grid): n = len(grid) new_grid = [[0] * n for _ in range(n)] for r in range(n): for c in range(n): new_grid[n - 1 - c][n - 1 - r] = grid[r][c] return new_grid
Show answer & marking schemeHide answer & marking scheme
Worked solution
During a 90-degree clockwise rotation of an N x N matrix, the element at row `r` and column `c` (denoted `grid[r][c]`) moves to the new position where its new column index is determined by the old row index starting from the right side (`n - 1 - r`), and its new row index is equal to the old column index `c`. Thus, the correct mapping is `new_grid[c][n - 1 - r] = grid[r][c]`, which matches Option A.
Marking scheme
Grid initialization (4 marks): Instantiating a new N x N grid populated with default values safely without aliasing. Row transformation (4 marks): Mapping the original row 'r' to the new column index 'n - 1 - r'. Column transformation (3 marks): Mapping the original column 'c' to the new row index 'c'. Algorithmic correctness (2.33 marks): Choosing Option A as the only function with correct index math.
Question 6 · multiple-choice
13.33 marks
A developer is writing a robust Python function `count_even_integers_in_file(filename)` that opens a text file, reads numbers from it (where each number is stored on a separate line), and returns the count of even integers.
The function must: 1. Safely handle cases where the file does not exist by returning `-1`. 2. Ignore any lines that cannot be successfully cast to an integer (e.g., blank lines or text words) and continue processing the rest of the file. 3. Close the file properly regardless of any read/parse errors.
Which of the following implementations correctly satisfies all these requirements?
count = 0 try: for line in f: try: num = int(line.strip()) if num % 2 == 0: count += 1 except ValueError: continue finally: f.close() return count
B.def count_even_integers_in_file(filename): try: with open(filename, 'r') as f: count = 0 for line in f: num = int(line.strip()) if num % 2 == 0: count += 1 return count except FileNotFoundError: return -1 except ValueError: return 0
C.def count_even_integers_in_file(filename): f = open(filename, 'r') count = 0 for line in f: try: num = int(line.strip()) if num % 2 == 0: count += 1 except Exception: pass f.close() return count
D.def count_even_integers_in_file(filename): try: f = open(filename, 'r') count = 0 for line in f: num = int(line) if num % 2 == 0: count += 1 return count except FileNotFoundError: return -1 finally: f.close()
Show answer & marking schemeHide answer & marking scheme
Worked solution
Option A is correct because: 1. The outer `try-except FileNotFoundError` block catches missing files and returns `-1` immediately. 2. Once the file is opened, an inner `try-finally` block wraps the loop to ensure that `f.close()` is executed even if a fatal error occurs. 3. Inside the loop, another `try-except ValueError` block surrounds the `int(line.strip())` casting. This ensures that any line containing non-integer content only raises a local exception, which is caught, allowing the loop to continue safely to the next lines without aborting the entire function. Option B, by contrast, terminates the function and returns `0` upon encountering the first non-integer value because its `except ValueError` is located outside the loop.
Marking scheme
Missing file handling (4 marks): Handled FileNotFoundError correctly using an outer exception block. Resilience to formatting errors (4 marks): Placed try-except ValueError inside the loop body to permit continuing parsing subsequent lines. Resource management (3 marks): Guaranteed closing the file with a finally block on open success. Correct logic integration (2.33 marks): Correctly combined nested exception structures.
Wondering how well you actually know this?
Thinka is an AI practice app for DSE students — unlimited questions, instant auto-marking, and detailed step-by-step solutions. 100,000+ students use it to confirm they actually know it, not just think they do.