NCL 108: Making Decisions with Numbers
In NCL 102, we used MOD to find the remainder after division.
For example:
MOD r0 10 2
stores the remainder from dividing 10 by 2.
Because even numbers divide evenly by 2, their remainder is 0.
Odd numbers leave a remainder of 1.
At the time, we didn't do anything with that information.
Now we can.
Checking one number
Let's choose a number with a constant:
#number 7
We want the program to determine whether that number is even or odd.
The number itself does not change while this program runs, so a constant is a good fit.
We also need somewhere to store the remainder produced by MOD.
That value is calculated while the program runs, so it needs a register:
#remainder r0
Now we can calculate:
MOD #remainder #number 2
If #number is even, #remainder will contain 0.
If #number is odd, #remainder will contain 1.
Using the result
Once we know the remainder, we can use it to choose what the program does next.
#remainder r0
#number 7
MOD #remainder #number 2
BEQ $even #remainder 0
D.TXT "Odd"
JUMP $done
$even
D.TXT "Even"
$done
D.BLT
The important part is:
BEQ $even #remainder 0
This asks:
Is the remainder equal to
0?
If it is, the CPU branches to $even.
If it isn't, execution continues downward and the program writes:
Odd
Then:
JUMP $done
skips over the even path.
Following the odd path
With:
#number 7
the program calculates:
7 ÷ 2 leaves remainder 1
So:
MOD #remainder #number 2
stores 1 in #remainder.
The program then follows this path:
| Instruction | #remainder |
What happens |
|---|---|---|
MOD #remainder #number 2 |
1 | 7 leaves remainder 1 |
BEQ $even #remainder 0 |
1 | 1 is not equal to 0, so continue downward |
D.TXT "Odd" |
1 | Writes Odd |
JUMP $done |
1 | Skips the even path |
D.BLT |
1 | Makes the result visible |
The program displays:
Odd
Following the even path
Now change:
#number 7
to:
#number 8
This time:
8 ÷ 2 leaves remainder 0
So #remainder becomes 0.
The path changes:
| Instruction | #remainder |
What happens |
|---|---|---|
MOD #remainder #number 2 |
0 | 8 leaves remainder 0 |
BEQ $even #remainder 0 |
0 | The values are equal, so branch to $even |
D.TXT "Even" |
0 | Writes Even |
D.BLT |
0 | Makes the result visible |
The program displays:
Even
The calculation itself has changed which path the program follows.
The program is no longer branching because we already knew what should happen.
It calculates some information first, then uses that information to decide.
Try another number
Change only:
#number 8
Try several different values.
Before running the program, predict the result.
What remainder will MOD produce?
Will BEQ branch to $even, or will execution continue downward?
Then run the program and see whether you were right.
Checking more than one number
So far, #number has been a constant:
#number 7
That works because the program checks one number and never changes it.
What if we want to check every number from 1 through 10?
Now the number needs to change while the program runs.
A constant is no longer the right tool.
Instead, we'll use a register:
#number r0
#remainder r1
#limit 10
#number is now an alias for r0.
#remainder is an alias for r1.
#limit remains a constant because the limit stays fixed.
We can begin with:
MOVE #number 1
and increase the number each time through a loop.
Putting the decision in a loop
Here's the complete program:
#number r0
#remainder r1
#limit 10
MOVE #number 1
$again
D.TXT #number
D.TXT ":"
MOD #remainder #number 2
BEQ $even #remainder 0
D.TXT "Odd "
JUMP $next
$even
D.TXT "Even "
$next
INC #number
BLE $again #number #limit
D.BLT
The program displays:
1:Odd 2:Even 3:Odd 4:Even 5:Odd 6:Even 7:Odd 8:Even 9:Odd 10:Even
There are several things happening in each trip through the loop.
First:
D.TXT #number
D.TXT ":"
writes the current number.
Then:
MOD #remainder #number 2
calculates whether that number divides evenly by 2.
The result controls this branch:
BEQ $even #remainder 0
If the remainder is 0, the CPU follows the even path.
Otherwise, it follows the odd path.
Both paths eventually reach:
$next
Then:
INC #number
moves to the next number.
Finally:
BLE $again #number #limit
decides whether the loop should continue.
Following two trips through the loop
Let's trace the first two numbers.
The program begins with:
#number = 1
Then:
| Step | #number |
#remainder |
What happens |
|---|---|---|---|
| Start | 1 | First number to check | |
MOD #remainder #number 2 |
1 | 1 | 1 leaves remainder 1 |
BEQ $even #remainder 0 |
1 | 1 | Not equal, so follow the odd path |
D.TXT "Odd " |
1 | 1 | Writes Odd |
INC #number |
2 | 1 | Move to the next number |
MOD #remainder #number 2 |
2 | 0 | 2 leaves remainder 0 |
BEQ $even #remainder 0 |
2 | 0 | Equal, so branch to $even |
D.TXT "Even " |
2 | 0 | Writes Even |
INC #number |
3 | 0 | Move to the next number |
The same pattern continues until #number passes #limit.
The important part is not the even-and-odd test itself.
It is the relationship between these instructions:
MOD #remainder #number 2
BEQ $even #remainder 0
The first instruction calculates a value.
The second uses that value to choose what happens next.
Calculations can guide control flow
This is a pattern you'll use often.
A program can:
- calculate something,
- store the result,
- compare that result,
- and choose a path based on what it found.
Here, the calculated information is a remainder.
In another program, it might be a total, a distance, a score, a counter, or any other value the program is working with.
The CPU does not need to know what the number means.
It only needs instructions that tell it how to calculate the value and what to do with the result.
Try it
Start with:
#number r0
#remainder r1
#limit 10
MOVE #number 1
$again
D.TXT #number
D.TXT ":"
MOD #remainder #number 2
BEQ $even #remainder 0
D.TXT "Odd "
JUMP $next
$even
D.TXT "Even "
$next
INC #number
BLE $again #number #limit
D.BLT
Change:
#limit 10
to another value.
Predict how many numbers the program will check.
Then try changing:
MOD #remainder #number 2
to:
MOD #remainder #number 3
The program's messages will no longer describe the calculation correctly, but follow the program anyway.
Which numbers produce a remainder of 0?
When does the branch to $even happen?
What property is the program actually detecting now?
In NCL 109: Choosing Between Many Paths, we'll return to that last example and make the program handle all three possible remainders separately.