Suppose you are given an IPv4 CIDR address

`153.10.22.56 /22 `

This IP address represents a particular device (“host”, in networking terminology) on a network, such as a laptop computer or gaming system.

From this simple set of numbers you can calculate all sorts of things about the network it belongs to, such as the network’s starting address, the number of devices (“hosts”, in networking terminology) the network supports, and the ordinal number in the network of this particular device. Let’s go be leet hackers…

The number after the “/” indicates what portion of the network address belongs to the network itself, and which portion is available for hosts. In the case of /22, it means the first 22 bits are used for the network itself, and the remaining 10 bits can be used by the various hosts that join the network.

In a 32-bit binary number, the first 22 bits should be 1’s, and the rest 0’s.

`11111111 11111111 11111100 00000000 // that's 22 1's`

Convert each “chunk” back to decimal and you get:

`255.255.252.0  // the netmask! `

Now that we know the network mask, we can figure out the network’s address. The network address is the address of the network itself and it is the lowest address on the network.

If you’ve ever poked around your own home network, you might recognize 192.168.1.0 (or similar). All devices that join the network are given a similar, higher-numbered IP address when they are on the network: your phone might be 192.168.1.05, your laptop might be 192.168.1.12, etc.

You can find the network’s address by using your knowledge of the IP address of any given device on the network and the netmask.

Start by converting the IP address and the netmask to binary. Then, perform a bitwise and, meaning that for any position that has two 1’s, the result will be a 1. (Two zeroes or a 1 and a zero results in a 0.)

```153.10.22.56        10011001 00001010 00010110 00111000
255.255.252.0       11111111 11111111 11111100 00000000
--------------------------------------
Bitwise AND:        10011001 00001010 00010100 00000000```

Convert the result of the bitwise and back to decimal to get your network address:

`153.10.20.0        // the network address!`

Sanity check: The network address is always the lowest address on the network, so it makes sense that a device found at 153.10.22.56 could be somewhere in a network that began its addresses at 153.10.20.0. You should be suspicious of your result if you end up with a network address that is higher than the IP you were given to start with.

Go back to your network mask result in binary and flip the 1’s and 0’s to get the host mask:

```11111111 11111111 11111100 00000000 // network mask
00000000 00000000 00000011 11111111 // host mask (bits flipped)```

You may wish to convert it to decimal:

`0.0.3.255`

Sanity check: Since the host mask is just the opposite of the network mask, you might able to “eyeball it” by finding the difference between each portion of the address and 255. For the given netmask, 255.255.252.0, you could subtract 255-255 = 0 for the first two parts, 255-253 = 3 for the second-to-last part, and 0-255=|-255| for the last part. Be suspicious of any result you get that doesn’t appear to be the “inverse” of the net mask you started with.

To find it, use the IP address you started with and the host mask from the previous step. Perform a bit mask on them, meaning that anywhere you have a 1 is good enough to get a 1 in the result. Two 1’s = 1 and a 0 and a 1 = 1.

```153.10.22.56        10011001 00001010 00010110 00111000  // IP
0.0.3.255        00000000 00000000 00000011 11111111  // host mask
--------------------------------------

`153.10.23.255  // the broadcast address!`

## Find the number of possible hosts

To find the maximum number of hosts a network can support, go back to that “/22” from the IP address you started with. Subtract it from 32. (Why 32? Because that’s how many bits are in an address, total.)

`32 - 22 = 10`

Now raise 2 to that power:

`2^10 = 1024`

And subtract 2:

`1024 - 2 = 1022  // hopefully that's enough room for everyone `

We subtract 2 because there are two reserved host numbers: the network address itself, and the broadcast address. We can’t assign those to laptops and smart TVs so we don’t include them in the maximum number of supported hosts.

## Find the host number

My class often asked us for the “host number” of a device but didn’t really explain what was meant by that or how to calculate it.

The host number is just the ordinal number of the host on the network. It’s the Nth device on the network. Pretend you’ve already got a printer, a TV, and a computer on your network. You add your phone. Your phone is the 4th device to join. Its host number is 4.

In other words, you’re not looking for an IP address here, you’re looking for an ordinal number. For the sake of questions like the ones I got in CS372, you’re also assuming that hosts were added “in order” and assigned their IP addresses accordingly.

You need to know both the network’s address and the IP of the device itself. it from the IP if you know where the network starts.

```153.10.22.56   // this is where we are, what is our host number?
153.10.20.0    // this is where the network starts```

I imagine each section of the IP address to be like a bucket. Each bucket holds 255. Once a 256th is added, the number to its left has to increase by 1 and that bucket is reset to 0. (This is just like “carrying over” a number the way we’ve done since elementary school.)

Let’s do an easy one first.

```153.10.20.0   // this is where the network starts
153.10.20.1   // what host number am I?```

The device at 153.10.20.1 is host number 1. It’s the first host on the network because 153.10.20.0 is reserved as the network’s own address.

Here’s a harder one:

```153.10.20.0    // this is where the network starts
153.10.20.255  // what host number am I?```

The device at 153.10.20.255 is host number 255.

Now let’s see what happens when the number to the left also changed.

```153.10.20.0    // this is where the network starts
153.10.21.1   // what host number am I?```

Hey, that 20 became a 21! We must have added a lot of hosts to this network. We added so many, that the 153.10.20.nnn space was exhausted and we had to increase 20 to 21 and start numbering over. This “carry over” is just like you did in elementary school math, except here the limit is 255.

Since this is where it gets complicated, I’ll show you the steps:

`153.10.20.0    // this is where the network starts153.10.21.1   // what host number am I?`
```20 - 21 = 1    // there was 1 "carry over"
1 * 255 = 255  // which means 255 hosts were added...
255 + 1 = 256  // and there's still 1 in the far-right bucket
256 + 1 = 257  // add that 1 from the first line to account for reserved addresses```

The device at 153.10.21.1 is host number 257.

Hopefully you see the pattern here: each section is like a “bucket” that can be filled to 255, and then it has to “carry over” to the left and get reset to 0.

Now that you know how it’s calculated, we can look at “reverse engineering” it from our problem’s IP address.

```153.10.20.0    // this is where the network started
153.10.22.56   // this is where we are, what is our host number? ```
```22 - 20 = 2     // two "carry overs" in the bucket
2 * 255 = 510   // 510 were added to get from 20.0 to 22.0
510 + 56 = 566  // add the 56 from the last bucket
566 + 2 = 568   // add 2 from the first line```

The device at 153.10.22.56 is host number 568.

I think that last step is worth elaborating on a bit more. The 2 was added because 153.10.21.0 and 153.10.22.0 are also not used for devices. The 2 was derived from subtracting 20 from 22 (the second-to-last segment of the IP address).

### More host number examples

Example 1:

```128.193.42.0     // this is where the network starts
128.193.43.35    // this is where we are, what is our host number? ```
```43 - 42 = 1      // there was one "carry over"
1 * 255 = 255    // so we know at least that many hosts were added so far
255 + 35 = 290   // add the 35 from the furthest-right bucket
290 + 1 = 291    // add that 1 from the first step, we're host #291```

Example 2:

```128.193.0.0      // this is where the network starts
128.193.43.35    // this is where we are, what is our host number?```
```43 - 0 = 43          // that's a lotta "carry overs"
43 * 255 = 10965
10965 + 35 = 11000
11000 + 43 = 11043   // we're host #11043```

## Networking – how to solve the “find the utilization for a TCP sender that is continuously sending” problem

In this post: A detailed, step-by-step guide demonstrating the steps I use to solve a problem similar to one encountered in my CS 372 Intro to Networking class.

You have a TCP sender that is continuously sending a 1,096-byte segment. If a TCP receiver advertises a window size of 8,551 bytes, and with a link transmission rate 35 Mbps an end-to-end propagation delay of 33.3 ms, what is the utilization?

(Assume no errors, no processing or queueing delay, and ACKs transmit instantly. Also assume the sender will not transmit a non-full segment.)

Suppose they want the answer as a percentage rounded to one decimal place.

This one breaks down into a series of simple steps:

## Step 1: Calculate how many segments the pipeline holds

```formula:
segments = floor(pipeline size / segment size)```
```8551 / 1096 = 7.802
= 7 segments```

Remember to round down! There are no partial segments in this pipeline.

## Step 2: Calculate how long it takes to send one segment

This uses the L/R formula, which is:

```formula:
time to send one segment = length of segment / transmission rate```

(Don’t forget to use the same units for both. I convert everything to bits for consistency.)

`(1096 * 8) / (35 x 10^6) = 0.250514 time to send one segment`

## Step 3: Calculate the Round Trip Time (RTT)

```formula:
RTT = propagation delay * 2 ```
`33.3 * 2 = 66.6 round trip time`

## Step 4: Calculate the delay per packet

```formula:
delay per packet = RTT + time to send one```
`66.6 + 0.250514 = 66.850514 delay per packet`

## Step 5: Calculate the utilization!

```formula:
utilization = (segments * time to send one) / delay per packet```
`(7 * 0.250514) / 66.850514 = 0.026316`

Move the decimal to places to the right to get the percentage.

`= 2.6% utilization`

## Networking – how to solve the “effective delay” problem

In this post: A detailed, step-by-step guide demonstrating the steps I use to solve a problem similar to one encountered in my CS 372 Intro to Networking class.

Given an effective delay of 99ms when network usage is 76%, what is the effective delay when network usage is 53%?

Suppose they want the answer in milliseconds rounded to 1 decimal place.

You might’ve seen a variation of this problem where the delay is given in ms and the network usage is 0%. If you’re given a delay with a network that’s in-use, you have to first figure out what the the delay would be if the network congestion was 0%.

Let’s call that value x and solve for it.

We will use the same D = Do/(1-U) formula we would use if we already knew the delay for a zero-congestion network, but we will put our 99 ms delay where D goes and our unknown “x” value for Do.

```Do / (1 - U) = D
x / (1- 0.76) = 99ms
x / (0.24) = 99```

Multiply both sides by 0.24 to turn that into a value for x:

```x = 0.24 * 99
x = 23.76 <-- network delay in ms when congestion is at 0%```

Now that we know the delay in ms when congestion is at 0%, we can plug it into the D = Do/(1-U) formula again.

```D = 23.76 / (1 - .53)
D = 50.6 ms```

It’s not a difficult problem but my class’s materials only covered the “easy” version so I wanted to demonstrate the “missing steps” for anyone else who might be wondering what to do when they give you the delay for a partially-congested network instead.

## Networking – how to calculate the size of MSS for a “mythical set of protocols”

In this post: A detailed, step-by-step guide demonstrating the steps I use to solve a problem similar to one encountered in my CS 372 Intro to Networking class.

Imagine a mythical set of protocols with the following details:

• Maximum Link-Layer data frame: 1,331 bytes
• Network-Layer header size: 29 bytes
• Transport-Layer header size: 34 bytes

What is the size, in bytes, of the MSS?

`1331 - 29 - 34 = 1268`

You just subtract the header sizes from the data frame. Easy.

You probably could’ve guessed that, but if you’re in CS372 and you’re reading this then it might be because you weren’t 100% sure wanted to check your work but the class materials didn’t really cover it. And that’s the thing that irked me about this problem: the class just threw it at us as a surprise on the weekly (graded but open-book) exercises in week 6. Then you go a-Googlin’ and end up somewhere like chegg.com who wants \$15 to sell you a solution! That’s just silly.

Now you know: calculating the maximum segment size is just a simple subtraction problem.

## Networking – how to solve the “non-persistent vs persistent HTTP” problem

In this post: A detailed, step-by-step guide demonstrating the steps I use to solve a problem similar to one encountered in my CS 372 Intro to Networking class.

A client’s browser sends an HTTP request to a website. The website responds with a handshake and sets up a TCP connection. The connection setup takes 2.5 ms, including the RTT. The browser then sends the request for the website’s index file. The index file references 2 additional images, which are to be requested/downloaded by the client’s browser. How much longer would non-persistent HTTP take than persistent HTTP?

Suppose they want the answer in milliseconds rounded to 2 decimal places.

You can get fancy with writing out each and every request (and this is what they’ll show in the worksheet), but there’s a faster way, especially if the number of referenced objects is more than a few.

Step 1: Count the total number things you’re getting, ie: 1 index file + 3 images = 3. That’s your N value.

`index.html + image1.jpg + image2.jpg = 3 things total`

Step 2: For non-persistent HTTP, your answer will be the result of N x 2.

`3 x 2 = 6 connections needed for non-persistent HTTP`

(That’s because for each and every item you request, you also need to request a TCP connection.)

1. TCP request
2. index.htm request
3. TCP request
4. image1.jpg request
5. TCP request
6. image2.jpg request

Step 3: For persistent HTTP, do N+1

`3 + 1 = 4 connections needed for persistent HTTP`

(That’s because you only need to connect once, and then request all the things you want.)

1. TCP request
2. index.htm request
3. image1.jpg request
4. image2.jpg request

Step 4: Now you have:

`6 connection requests for non-persistent HTTP`
`4 connection requests for persistent HTTP`

Step 5: Find the difference.

`6 - 4 = 2`

Non-persistent HTTP needs 2 more connections than persistent.

Step 6: Multiply that difference by how long each connection takes to set up.

`2 x 2.5 milliseconds = 5 milliseconds. `

Double-check your rounding and units! You might be asked to give this in seconds instead of milliseconds.

### In summary

• Sum the things (index file and images) to get N
• Non-persistent HTTP = N x 2
• Persistent HTTP = N + 1
• Find the difference
• Multiply the difference by how long a round trip takes

## Networking – how to solve the “fileX and fileY” problem

In this post: A detailed, step-by-step guide demonstrating the steps I use to solve a problem similar to one encountered in my CS 372 Intro to Networking class.

You’re given a link with a maximum transmission rate of 70.5 Mbps. Two computers, X and Y, want to transmit starting at the same time. Computer X sends File X (18 MiB) and computer Y sends File Y (130 KiB), both starting at time t = 0.

• Statistical multiplexing is used, with details as follows
• Packet Payload Size = 1000 Bytes
• Ignore Processing and Queueing delays
• Assume partial packets (packets consisting of less than 1000 Bytes of data) are padded so that they are the same size as full packets.
• Assume continuous alternating-packet transmission.
• Computer X gets the transmission medium first.

At what time (t = ?) would File X finish transmitting?

Suppose they want the answer in seconds (hah – not milliseconds like usual!) and they want it rounded to two decimal places.

The “twist” of this problem is that File X and File Y take turns being sent in little chunks of 1000 bytes (plus 24 bytes of overhead).

First a piece of X goes, then a piece of Y, then back to X, etc.

Y is smaller so you run out of Y before you run out of X, but fortunately for us, this problem wants to know when X is done being sent. So really what we’re looking for is how long it takes to send both X and Y.

Here’s a drawing I made to visualize the problem (obviously, X and Y are both way more than just 10 and 5 packets in our real problem). Diagram depicting X1, Y1, X2, Y2, X3, Y3, X4, Y4, X5, Y5, X6, X7, X8, X9, X10 interwoven with each other. Each block represents a packet.

Step 1: Figure out how many packets have to be sent, total

Our packet size (1000 bytes) and our overhead size (24 Bytes) are given in bytes, so I’m going to turn the two filesizes into Bytes instead of bits for this one. (We can always turn it into bits later if needed.)

```File X = 18 MiB // turn to bytes by multiplying by 1024 twice
= 18 * 1024 * 1024
= 18874368 bytes```
```File Y = 130 KiB // turn to bytes by multiplying by 1024 once
= 130 * 1024
= 133120 bytes```

Now X and Y are in the same units (bytes) and we can use that to figure out how many packets of 1000 bytes each one would be divided into.

`File X = 18874368 Bytes / 1000 = 18874.368 packets`

Our result isn’t a whole number. What should we do with the “partial packet”? Well, the problem tells us that any partial packets should be padded up to a full size. In practice, this just means we round up to the next nearest whole number. 18874.368 becomes 18875 packets for File X.

Now do the same for File Y:

```File Y = 133120 Bytes / 1000 = 133.12
Round up to get 134 packets for File Y```

(Save these numbers for later, we’ll come back to them.)

Step 2: Calculate the time needed to send one packet plus its overhead

Add the packet size and the overhead size (both must be in the same units; here, that’s bytes but your variation of this problem may differ). Since transmission rate is in bits, let’s also multiply the packet size + overhead size by 8 to put it in bits, and multiply the transmission rate by 10^6 to put it in bits also. That looks like…

```L/R, where R's units is what the outcome of this calculation will be
= (1000 Bytes + 24 Bytes * 8) / (70.5 Mbps x 10^6)
= (8192) / (70.5 x 10^6)
= 0.0001161985816 seconds // same units as R (bits per second)
= 0.11619858156 msec // multiply by 1000 to get milliseconds```

We now know that it takes 0.11619858156 milliseconds to send one packet (and its overhead). Save this number for later.

Step 3: Calculate the time it takes to send all packets

This step is easy: we know how many packets we have between File X and File Y, and we know how long it takes to send one of them, so let’s figure out how long it takes to send all of them.

`18875 packets + 134 packets = 19009 packets to send`
`19009 packets x 0.11619868156 msec = 2208.820738 milliseconds to send all `

Step 4: Convert to seconds and round to 2 decimal places to get the final answer

This variation of the problem wants the solution in seconds, so divide our result from Step 3 by 1000 to get 2.208820738 seconds and round it to two decimal places to get 2.21 seconds, which is when time at which File X will be done sending.

What if it wanted to know when the smaller file was done sending?

Well, let’s look at our diagram again. Here we can see that for every packet of Y sent, a packet of X has already been sent. For every packet of Y that is sent, one from X precedes it. In other words, to send all 5 packets of Y we must also send 5 packets of X.

We know Y is made up of 134 packets, so that many packets of X will also be sent. That means for our final answer all we have to do is figure out how long it’ll take to send 134*2 packets.

```134 * 2 = 268 // all of Y + same amount of X
268 packets x 0.11619868156 msec = 31.14124666 msec to send File Y```

Convert that answer to seconds and there we have it: 0.03 seconds have elapsed when File Y (the smaller file) is done sending.

## Networking – how to solve the “routers in a sequence” problem

In this post: A detailed, step-by-step guide demonstrating the steps I use to solve a problem similar to one encountered in my CS 372 Intro to Networking class. Yeah, I’m still cranky that this class makes no effort to teach this stuff. They just send you a-Googlin’. Welcome, Googlers…

Suppose there are 3 routers in sequence between Host A and Host B, all of which use store-and-forward routing. What is the total end-to-end delay for a packet originating from Host A with destination Host B, under the following conditions.

• Each of the link transmission rates are 5.1 Mbps
• The total distance from Host A to Host B along its path of transmission is 175.1 km
• The speed of propagation through the transmission medium is is 2.7 x 108 m/s
• The packet size is 2 KiB

Remember that you must also uplink from Host A to the first router. Suppose this one wants the answer in milliseconds rounded to 1 decimal place.

Step 1: Figure out the transmission delay for one link

The “twist” of this problem is that there are multiple transmission delays to account for. Every “hop” incurs a transmission delay.

We can use the L/R formula with the known packet size (2 KiB and known transmission rate (5.1 Mbps) to calculate the transmission delay for one node to another. Node here means host or router. Be sure to convert both into bits.

```(2 KiB * 8192) / (5.1 Mbps * 10^6)
= 16,384/5,100,000 = 0.00321254... seconds```

Remember that the units R is in determines the outcome, so this result is in seconds. Multiply it by 1000 to turn it into milliseconds and save this result for later.

`0.00321254 x 1000 = 3.21254901... milliseconds`

Step 2: Figure out the entire path’s transmission delay

Recall that our three routers and two hosts basically look like this:

[A]––––[B]

We know the transmission delay (the time it takes for a bit to be placed on the transmission medium) at one host or router, and we know how many routers there are total, so we can figure out how many “transmission delays” our bits will go through by multiplying the total number of routers plus one (to account for being placed on the transmission medium by A) by the transmission delay we calculated in step 1.

```(R + 1) * 3.21254901  // R is the number of routers
= (3 + 1) * 3.21254901 // add 1 to account for initial link
= 4 * 3.21254901
= 12.85019604 milliseconds```

This number represents the total amount of transmission delay experienced by bits traversing this multi-router path.

Step 3: Figure out the propagation delay

Recall that our distance is 175.1 km and our speed of propagation is 2.7 x 108 m/s and the propagation delay formula is Tprop = d/s. Note that km has to be turned into meters and the result will be in seconds.

`= (175.1 * 1000) / (2.7 x 108 m/s) = 0.0006485185... seconds `
`0.0006485185... seconds x 1000 = 0.64851 milliseconds`

Step 4: Add it all up

` 3.21254901 + 12.85019604 + 0.64851 = 16.71125505 milliseconds`

And that’s it, you’re done! Hope you found this helpful!

## Networking – how to solve the “VOIP problem”

In this post: A detailed, step-by-step guide demonstrating the steps I use to solve a problem similar to one encountered in my CS 372 Intro to Networking class.

### The “VOIP problem”

You’re given a diagram (you won’t need it) and some values in the form of…

• Host A converts analog to digital at a = 40 Kbps
• Link transmission rate R = 4.2 Mbps
• Host A groups data into packets of length L = 51 bytes
• Distance to travel d = 900 km
• Propagation speed s = 2.5 x 108 m/s
• Host A sends each packet to Host B as soon as it gathers a whole packet.
• Host B converts back from digital to analog as soon as it receives a whole packet.

The question asks, How much time elapses from when the first bit starts to be created until the conversion back to analog begins?

Let’s say they want the answer in milliseconds rounded to two decimal places (note: this varies – sometimes the answer has to be in seconds, sometimes they want it rounded to one decimal place – double check your instance of the problem!)

Step 1: Figure out how long it takes to make a single packet

“When the first bit starts to be created” means “when this imaginary machine starts building the very first packet”.

We know how big a packet is: 50 bytes.

We know the rate at which it produces packets: 40 Kbps.

This is the classic L/R (length over rate) you’ve hopefully seen if you’re keeping up with the course materials. We can use L/R here, but we have to turn 51 bytes into bits (multiply it by 8) and we have to turn 40 Kbps into bps (multiply it by 1,000).

`(51 * 8) / (40 * 1,000) = (408 / 40,000) = 0.0102 seconds`

We get 0.0102 seconds because the units that R is in determines the outcome. R is in bits per second (bps), so that’s how we know the units we’re looking at here is seconds.

We need this in milliseconds, because we’re going to put everything in milliseconds so that we’re working in the units the question expects. Multiply the seconds answer by 1000 to get milliseconds, like so:

`0.0102 x 1000 = 10.2 milliseconds`

That’s the time it takes to make one single, complete, ready-to-transmit packet. Save this value for later, we will come back to it in step 4.

Step 2: Figure out the transmission delay

Recall from the course materials that transmission delay is the time it takes to place every bit onto the transmission medium. Transmission delay is not the time it takes to actually send it!

If you like car analogies, consider transmission delay the time it takes to get your car onto the highway. Your car is being placed on the transmission medium, and the time it takes to do that is the transmission delay. (Again, this is not the time it takes to travel the length of the highway! It’s the time it takes to get your car onto the highway.)

We will use the L/R formula again for this step. This time L is the length of the packet (51 bytes) and R is the transmission rate (4.2Mbps). We need both of them in bits, so multiply 51 (bytes) by 8 to get bits, and multiply 3.8 by 1,000,000 to get bps.

`(51 * 8) / (3.8 x 1,000,000) = (408 / 3,800,000) = 0.00010737 seconds`

Again, the units of R determine what units the result is in, which in this case is seconds (because we had bits per second for our R).

To turn it into milliseconds, multiply by 1000:

`0.00010737 x 1000 = 0.10736842 milliseconds`

So, what do we have so far? We have the time it takes to make one packet and the time it takes to transmit that packet, both in milliseconds. There is one missing piece: propagation delay.

Step 3: Figure out the propagation delay

Propagation delay is the time it takes a bit to travel the given distance (900 km) at the given speed (2.5 x 108 m/s). The formula for propagation delay is d/s (distance over speed).

To go back to our car analogy, the propagation delay is the time it takes the car to zoom down the highway to its destination.

Like L/R, the d/s result will be in the same units as the bottom number (so, seconds). However, before we proceed, note that the distance we were given is in kilometers and the speed is given in meters per second. We need to convert kilometers to meters when we do our calculation, so multiply that 900 by 1,000.

`(900 km * 1,000 / 2.5 x 108) = 0.0036 seconds`

Remember to convert that answer to milliseconds:

`0.0036 x 1000 = 3.6 milliseconds`

Time to generate packet + time to place it on the transmission medium + time for it to propagate = our answer

`10.2 msec + 0.10736842 msec + 3.6 msec = 13.90736842 milliseconds`

Step 5: Round to the requested number of decimal places

Since this problem wants the answer rounded to two decimal places, 13.90736842 becomes 13.91

I hope this breakdown of the “VOIP problem” helps someone else!

I have to admit I’m a bit salty this class had us sit through all those lectures, read all those book chapters, and do all those worksheets and couldn’t once be bothered to expose us to even a watered-down or partial version of it before throwing it as us on a graded, timed quiz.

Fortunately, once you’ve mastered solving this problem, a lot of the other “math problems” that CS 372 throws at you in week 1 and week 2 will feel like variations on it.