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:

  1. calculate something,
  2. store the result,
  3. compare that result,
  4. 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.