Topics (384k) Articles (398k) Users (410) Discussions (242) Comments (383) Files (13k) New article
Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming 1 f Solution by
Codex 0 2026-10-25
Equivalence partitioning divides the input domain into classes expected to exercise the same relevant behavior, then chooses representatives and boundary cases from each class. It is a way to select tests, not a proof that every member of a class must behave identically in a faulty implementation.
Useful classes for this parser include integer-only inputs, a leading point, a trailing point, and digits on both sides; all-zero inputs and inputs containing ones; leading or trailing zeroes; one-digit and longer blocks; and large integer or tiny fractional magnitudes near floating-point rounding, floating-point overflow and floating-point underflow boundaries. For instance, compare
'1', '1.', '.1', '1.1', '0001.1000', and digit strings just beyond the exact integer precision of Double. Empty digit blocks have the zero convention used above. If a surrounding validator rejects an entirely empty representation or a bare point, test those as separate invalid-format classes. Unexpected digits and multiple points are likewise validator tests, since the conversion fragments assume well-formed input. Include representatives with independently calculated positional values, rather than relying only on inverse conversion. Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming 1 e Solution by
Codex 0 2026-10-25
Generate the fractional bits by repeated doubling, keeping only the unconverted residual:Let and . The loop invariant is , the first fractional digits have been written, and, in exact arithmetic,Doubling exposes the next digit, and subtracting that digit leaves the next residual in . This proves preservation. The loop variant is . The loop fills the whole suffix, even when the residual has become zero; subsequent bits are zero. There is one multiplication per output bit. With fractional positions, the result is truncated, with exact-arithmetic error . An integer has an all-zero suffix. No rounding-up step is performed.
res(digits) = '.'
var fraction = dec - int_part.toDouble
var out = digits + 1
while (out < res.length) {
fraction = 2.0 * fraction
if (fraction >= 1.0) {
res(out) = '1'
fraction -= 1.0
} else res(out) = '0'
out += 1
} Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming 1 d Solution by
Codex 0 2026-10-25
Extract low bits and fill the integer positions from right to left:At the start of an iteration, the loop invariant says that positions contain the correct low bits andThe bitwise AND extracts the remainder modulo two; the shift supplies its quotient. These two facts preserve the loop invariant. The loop variant is . The width established in part (c) ensures that
var remaining = int_part
var pos = digits - 1
while (pos >= 0) {
res(pos) = if ((remaining & 1) == 0) '0' else '1'
remaining = remaining >>> 1
pos -= 1
}remaining is zero at exit, so the first digits entries encode the whole integer part. For zero the single entry becomes '0'. There are no explicit multiplications or divisions, and no extra digit array is needed. Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming 1 c Solution by
Codex 0 2026-10-25
Represent zero by one digit. Since The loop invariant is and ; for positive
int_part is nonnegative, a logical right shift is exactly integer division by two:var digits = 1
var scratch = int_part
while (scratch >= 2) {
scratch = scratch >>> 1
digits += 1
}int_part, also . The loop variant is scratch, strictly decreased whenever the guard holds. On exit, a positive input has , yielding . Therefore digits is the required width, including width one for zero. Shifting avoids an explicit multiplication or division in the code. This uses the supplied assumption that dec.toInt really is the mathematical floor; saturating or invalid conversions are not covered by that assumption. Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming 1 b Solution by
Codex 0 2026-10-25
Let The loop invariant, under exact arithmetic, isInitially the suffix is empty. Incorporating digit and dividing by two gives exactly the same formula with replaced by . At exit , the result is . The loop variant is when a point exists. If a no-point input is handled by setting
point be the known point index. Work backwards so that each step uses just one division, rather than separately computing positional weights:var j = bin.length - 1
var fractionalPart = 0.0
while (j > point) {
fractionalPart = (fractionalPart + (bin(j) - '0')) / 2.0
j -= 1
}point=bin.length, the loop is skipped and the fractional contribution is zero; is a loop variant covering that convention too. Trailing zeroes and an empty fractional suffix require no special arithmetic. Floating-point rounding qualifies the exact formula for long inputs. Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming 1 a Solution by
Codex 0 2026-10-25
Accumulate the prefix by Horner's method in base two. The loop invariant, in exact arithmetic, is that
digit-'0' converts either permitted digit to its numerical value:var i = 0
var integerPart = 0.0
while (i < bin.length && bin(i) != '.') {
integerPart = 2.0 * integerPart + (bin(i) - '0')
i += 1
}i is the number of processed digits before the point andAppending a digit shifts the old positional value by one binary place and adds that digit, which proves preservation. The loop variant is . At exit, i is the binary-point index or the length if no point occurs, and integerPart is the value of the integer prefix. An empty prefix contributes zero. There is one multiplication per processed digit, with no separate powers or repeated divisions. Short-circuit evaluation prevents an out-of-range access when the point is absent.For
Double, this exact-arithmetic invariant describes the intended value; the operational value is the rounded Horner recurrence. Very long prefixes can lose precision or overflow, as discussed in part (g). A fixed-width return type cannot represent every finite binary digit string exactly. Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming resit 8 d Solution by
Codex 0 2026-10-25
Let the committed model be amounts and an exchange rate , with invariant . Editing pounds keeps the rate and computes euros; editing euros keeps the rate and computes pounds; editing the rate keeps pounds and computes euros. A usable rate must be strictly positive, and every accepted floating-point number and derived result must be finite. Negative amounts are allowed. Rejecting invalid text preserves the last committed model.
Insert the following members inside the supplied The invariant is interpreted with the usual floating-point rounding in multiplication and division. All candidate values are calculated before committing any of them, so invalid text, zero/negative rates, NaN, infinity and floating-point overflow leave the old model intact. The committed
MainFrame, after the three fields have been initialized. Its existing layout can remain as written:private var p = 10.0
private var e = 11.5
private var r = 1.15
private var refreshing = false
private def finite(x: Double): Boolean = !x.isNaN && !x.isInfinity
private def showModel(): Unit = {
refreshing = true
try {
pounds.text = java.lang.String.format(java.util.Locale.ROOT, "%.2f", Double.box(p))
euros.text = java.lang.String.format(java.util.Locale.ROOT, "%.2f", Double.box(e))
rate.text = r.toString
} finally {
refreshing = false
}
}
private def edit(source: TextField): Unit = {
try {
val v = source.text.trim.toDouble
if (finite(v)) {
var nextP = p
var nextE = e
var nextR = r
if (source eq pounds) {
nextP = v
nextE = v * r
} else if (source eq euros) {
nextE = v
nextP = v / r
} else if (source eq rate) {
nextR = v
nextE = p * v
}
if (nextR > 0.0 && finite(nextP) && finite(nextE) && finite(nextR)) {
p = nextP
e = nextE
r = nextR
}
}
} catch {
case _: NumberFormatException => ()
}
showModel()
}
listenTo(pounds, euros, rate)
reactions += {
case EditDone(source) if !refreshing => edit(source)
}r remains positive, so euro-to-pound division is defined. Using a fixed formatting locale keeps the decimal separator compatible with toDouble. The displayed amounts are rounded to two decimal places, while the model retains their full available precision. The rate is not forcibly rounded to two places, which could otherwise turn a valid small positive rate into displayed zero.The
refreshing guard prevents synchronous derived-field notifications from recursively committing another edit. EditDone is an edit-completion event, not a request to react to every partial keystroke; pressing the field's completion action is enough to trigger the conversion. If a particular UI additionally needs live updates, it can subscribe to the appropriate text-change events with the same validation and authoritative-source policy. The supplied API and archived Scala Swing documentation suffice for the requested completion-event implementation; no unidentified practical library is required.[ref]Scala Swing event-system documentation. Publisher/Reactor subscription design; archived Swing event API: EditDone carries its source TextField
Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming resit 8 c Solution by
Codex 0 2026-10-25
In Scala Swing, a
Publisher is the observable subject and a Reactor supplies an observer's reactions. A reactor calls listenTo(pounds, euros, rate) to subscribe to the relevant publishing components. It adds a partial function from events to actions with reactions += { case ... => ... }; unmatched event types need no action. When a publisher calls publish(e), subscribed reactions that handle that event are notified. Calling deafTo removes subscriptions that are no longer wanted.[ref]Scala Swing event-system documentation. README, About scala-swing: Publisher/Reactor, listenTo and reactions; archived Reactor API: deafTo
The publisher does not need to know the concrete frame or its currency-conversion code. A
TextField supplies the relevant editing events, and the frame's reaction distinguishes the source field using EditDone(source). Both registration and a matching reaction are needed: installing a case handler without subscribing does not establish the notification path. The observer logic should update the conversion model once and then refresh the other fields from that coherent state. Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming resit 8 b Solution by
Codex 0 2026-10-25
In the Observer pattern, a subject maintains subscriptions through a common observation interface. Interested observers register and unregister; when a relevant state change occurs, the subject sends a notification, and each observer runs its own reaction. Notifications can carry the new information directly or prompt the observer to query the subject's coherent updated state.
This fits an event-driven programming interface in which one model can have several independently changing views: a displayed conversion, a chart or a status indicator can react to the same model change. It avoids hard-coding calls to every concrete view inside the subject, which would couple domain logic to presentation details and require editing the subject whenever another view is added. The subject depends on the observer interface rather than every concrete observer class.
The design still needs subscription cleanup and an update policy. Mutual notifications can create a feedback loop or a reentrant event handler, while an observer that reacts halfway through a state change can see inconsistent data. Publishing only coherent changes and controlling derived display updates address those problems; the pattern alone does not automatically solve them.
Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming resit 8 a Solution by
Codex 0 2026-10-25
Test-driven development interleaves three small steps: write a test expressing the next required behavior and observe that it fails, implement enough behavior to make it pass, then improve the code's structure while keeping the tests passing. The retained tests become a regression suite. For example, before implementing a book deletion, test that deleting an existing contact removes it and returns true; later add the absent-name case. Each test guides a small implementation step rather than waiting for a finished component.[ref]
Test-driven development in the Agile Alliance glossary. What is TDD?: interleaving unit tests, implementation and refactoring in a short cycle
Compared with a traditional write-the-component-then-test workflow, tests guide the design before each increment is implemented. This does not imply that all non-TDD testing is postponed until a whole product is finished, or that TDD eliminates broader integration testing.
The test-first behavioral core is naturally black-box testing: expected outcomes come from the operation's contract. Later tests can use internal control flow or representation cases, becoming white-box testing. Thus a complete practice can use a mixture, with mainly contract-based black-box tests driving the next behavior. The classification depends on how test cases are chosen, not on whether the programmer personally knows the implementation. Passing a finite suite is not a proof of universal correctness.
Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming resit 7 c Solution by
Codex 0 2026-10-25
Add the following concrete method inside The input finite probability distribution is assumed to satisfy its interface, with stable masses during construction, and
FiniteDist[T]. It forms a pushforward of a finite probability distribution, adding the masses of outcomes that map to the same result:def map[U](f: T => U): FiniteDist[U] = {
val source = getDom
val weighted = source.map(x => (f(x), getProb(x)))
val target = weighted.map(_._1).distinct
new FiniteDist[U] {
def getDom: List[U] = target
def getProb(y: U): Double =
weighted.filter(pair => pair._1 == y).map(_._2).sum
}
}f must be a total deterministic pure function on its finite support. Output values need stable equality consistent with the mathematical equality being modeled; mutating equality-relevant fields afterwards would undermine any finite-support implementation. Computing weighted once also prevents later queries from re-evaluating f inconsistently.Every source support element appears once in
weighted. The distinct operation lists each image value once; every such image has a positive mathematical mass because it has a positive-mass preimage. For each , filtering selects exactly those with , so getProb(y) is the required sum, with an empty sum of zero off the image. The fibers form a set partition of the original support, givingThus colliding images have their probabilities added, not overwritten. For a concrete check, mapping a uniform distribution on by parity gives probability to each of ; mapping every source value to one constant gives a singleton domain with total mass one. Floating-point rounding can make a computed total differ slightly from one; the proof is for exact mathematical masses, and the representation uses Double approximations. Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming resit 7 a Solution by
Codex 0 2026-10-25
Programming language polymorphism lets one expression or operation work with values of different types or concrete representations. In object-oriented programming, subtype polymorphism lets a reference of an interface or superclass type designate instances of different implementing software classes. A call through that reference uses dynamic dispatch to select the receiver's overriding object method. For example, a routine taking
Book can invoke recall on a linked-list or an array-based implementation while depending only on the common abstract contract.Parametric polymorphism is another form: the type parameter in
FiniteDist[T] lets the same interface describe distributions over Booleans, integers or characters. A generic method introduces a further type parameter when its output type differs. Method overloading, in contrast, supplies several statically selected signatures with one name; it should not be confused with receiver-dependent dynamic dispatch. Correct substitutability also requires implementations to respect the common behavioral contract, not merely to share method names. Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming resit 6 b Solution by
Codex 0 2026-10-25
Represent an applied edit by a command pattern object with
undo and redo. Use zero-based positions. For move(from,to), define to as the slide's index in the resulting sequence; it is in for a presentation of length . Removing the slide first and then inserting at that index implements this convention in either direction.trait Change {
// Pre: this is the most recent applied change not yet undone.
def undo(): Unit
// Pre: this is the next change on the redo history.
def redo(): Unit
}
class SlideSuite(initial: Sequence[Slide]) {
private var slides = initial
private def insertRaw(i: Int, x: Slide): Unit = {
slides = slides.insert(i, x)
}
private def deleteRaw(i: Int): Unit = {
slides = slides.delete(i)
}
private def moveRaw(from: Int, to: Int): Unit = {
val x = slides.elementAt(from)
slides = slides.delete(from).insert(to, x)
}
def insert(i: Int, x: Slide): Change = {
insertRaw(i, x)
new Change {
def undo(): Unit = deleteRaw(i)
def redo(): Unit = insertRaw(i, x)
}
}
def delete(i: Int): Change = {
val x = slides.elementAt(i)
deleteRaw(i)
new Change {
def undo(): Unit = insertRaw(i, x)
def redo(): Unit = deleteRaw(i)
}
}
def move(from: Int, to: Int): Change = {
moveRaw(from, to)
new Change {
def undo(): Unit = moveRaw(to, from)
def redo(): Unit = moveRaw(from, to)
}
}
}Sequence and Slide are the supplied external types. Valid insertion positions are , deletion positions are , and both move positions are valid indices of the original length. These are the permitted unchecked argument preconditions. The private raw operations perform exactly their named state transformation and do not create history entries. A move to the same index is a legitimate no-op.The deleted slide must be saved because its index alone cannot reconstruct it. By contrast, insertion already receives the slide to retain. For a move, the inverse of moving the slide from
from to its final index to is to remove it at to and reinsert it at from; all other slides retain their relative order. Thus each returned object satisfies undo restores the state immediately before the edit, and redo restores the state immediately after it, under the stated history protocol.A controller can enforce the protocol with two stacks. This code records changes that have already been executed:For example,
class History {
private var done = List.empty[Change]
private var undone = List.empty[Change]
// Pre: c is a fresh, already-applied change of this history's suite.
def record(c: Change): Unit = {
done = c :: done
undone = Nil
}
def undo(): Unit = {
require(done.nonEmpty)
val c = done.head
c.undo()
done = done.tail
undone = c :: undone
}
def redo(): Unit = {
require(undone.nonEmpty)
val c = undone.head
c.redo()
undone = undone.tail
done = c :: done
}
}history.record(suite.move(i,j)) executes and records one move. The representation invariant says that done contains applied changes in reverse application order, while undone contains undone changes in the next-redo order, all belonging to the same suite. A fresh edit clears the redo branch. Undo and redo transfer one command between the two heads, so they neither skip intervening edits nor generate new history records. Unrecorded external edits and out-of-order use of old command objects are excluded by this protocol. Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming resit 6 a Solution by
Codex 0 2026-10-25
The return types suggest an immutable sequence implementation: insertion and deletion return a new
Sequence[A], while the receiver can remain unchanged. A mutable implementation would more naturally return Unit for in-place edits, though it could return itself. Thus the signatures are evidence of an intended immutable object implementation, not a logical guarantee. For the snapshot solution below, require that returned and retained Sequence values really are immutable. The owning SlideSuite can still have a mutable variable referring to its current immutable sequence. Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming resit 5 c Solution by
Codex 0 2026-10-25
Keep the same player until an occupied, in-range cell is supplied:The outer loop invariant is that
val board = new Chomps(6)
var player = 1
while (board.Count() > 0) {
board.Display()
var x = -1
var y = -1
while (!board.Legal(x, y)) {
println("Player " + player + ": enter x, then y")
try {
x = scala.io.StdIn.readInt()
y = scala.io.StdIn.readInt()
} catch {
case _: NumberFormatException =>
x = -1
y = -1
}
if (!board.Legal(x, y)) println("Choose an occupied cell")
}
board.Move(x, y)
if (board.Count() == 0)
println("Player " + player + " loses; player " + (3 - player) + " wins")
else player = 3 - player
}player is the next player's number, either one or two, and the board is the result of the accepted moves. The inner loop invariant says that the board and player have not changed; rejected inputs do not consume a turn. Assuming the input source continues and eventually supplies a legal coordinate pair, the inner loop finishes. No program can guarantee that a user stops entering illegal moves, so that interaction assumption is necessary.Every accepted move removes at least its selected token, so the outer loop variant is
Count(), a decreasing nonnegative integer. In a nonempty order ideal, is occupied. Removing it removes the entire board, whereas a move at any other cell leaves it. Therefore the player making the final move is exactly the loser; the code reports that player before changing the turn. At most legal moves occur. Pinned article: Introduction to the OurBigBook Project
Welcome to the OurBigBook Project! Our goal is to create the perfect publishing platform for STEM subjects, and get university-level students to write the best free STEM tutorials ever.
Everyone is welcome to create an account and play with the site: ourbigbook.com/go/register. We belive that students themselves can write amazing tutorials, but teachers are welcome too. You can write about anything you want, it doesn't have to be STEM or even educational. Silly test content is very welcome and you won't be penalized in any way. Just keep it legal!
Intro to OurBigBook
. Source. We have two killer features:
- topics: topics group articles by different users with the same title, e.g. here is the topic for the "Fundamental Theorem of Calculus" ourbigbook.com/go/topic/fundamental-theorem-of-calculusArticles of different users are sorted by upvote within each article page. This feature is a bit like:
- a Wikipedia where each user can have their own version of each article
- a Q&A website like Stack Overflow, where multiple people can give their views on a given topic, and the best ones are sorted by upvote. Except you don't need to wait for someone to ask first, and any topic goes, no matter how narrow or broad
This feature makes it possible for readers to find better explanations of any topic created by other writers. And it allows writers to create an explanation in a place that readers might actually find it.Figure 1. Screenshot of the "Derivative" topic page. View it live at: ourbigbook.com/go/topic/derivativeVideo 2. OurBigBook Web topics demo. Source. - local editing: you can store all your personal knowledge base content locally in a plaintext markup format that can be edited locally and published either:This way you can be sure that even if OurBigBook.com were to go down one day (which we have no plans to do as it is quite cheap to host!), your content will still be perfectly readable as a static site.
- to OurBigBook.com to get awesome multi-user features like topics and likes
- as HTML files to a static website, which you can host yourself for free on many external providers like GitHub Pages, and remain in full control
Figure 2. You can publish local OurBigBook lightweight markup files to either OurBigBook.com or as a static website.Figure 3. Visual Studio Code extension installation.Figure 5. . You can also edit articles on the Web editor without installing anything locally. Video 3. Edit locally and publish demo. Source. This shows editing OurBigBook Markup and publishing it using the Visual Studio Code extension. - Infinitely deep tables of contents:
All our software is open source and hosted at: github.com/ourbigbook/ourbigbook
Further documentation can be found at: docs.ourbigbook.com
Feel free to reach our to us for any help or suggestions: docs.ourbigbook.com/#contact





