Jupiter Ace - FORTH Programming

Steven Vickers

<== go back


Chapter 17

Other ways of counting

In English, as in most language, counting proceeds in blocks of ten: after a bit of initial wavering, it settles down as

twenty, twenty-one, . . ., twenty-nine
thirty, thirty-one, . . ., thirty-nine
and so on.

This grouping into tens is reflected even more rigidly in the usual way of writing numbers, with ten digits 0, 1, 2, 3, 4, 5, 6, 7, 8, and 9.

Mathematically speaking, ten is nothing special as a number and we use it simply because humans have ten fingers each – in fact digit really just means finger. Penguins would never dream of counting in tens, because they have two flippers instead of ten fingers. They count in twos.

How do they make this work? First, instead of our ten digits 0 to 9, they have just two penguin digits, 0 and 1. They also call them bits instead of digits. When a penguin starts counting it manages 0 and 1 all right, but then gets stuck because there are no more bits for it to use. We would go on to 2 because we've got eight more digits available to take us up to 9, but then we get stuck in the same way.

Our answer is to start using pairs of digits instead of single ones: after 9 comes 10, meaning one ten and no units. The penguin answer is exactly the same, except that they have to start using it much earlier: having run out of bits with one, they write two as 10, and three as 11. Then they get stuck again, so they apply the same process a further stage and write four as 100.

NumberHuman digitsPenguin bits
Nought 0 0
One 1 1
Two 2 10
Three 3 11
Four 4 100
Five 5 101
Six 6 110
Seven 7 111
Eight 8 1000
Nine 9 1001
Ten 10 1010
Eleven 11 1011
Twelve 12 1100
Thirteen 13 1101
Fourteen 14 1110
Fifteen 15 1111
Sixteen 16 10000

If you want to pretend to be a penguin, type

2 BASE C!
so that you can add 10 and 10 to get 100:
10 10 + .

BASE is a variable provided by the computer itself, a system variable. However, unlike ordinary variables its value is just one byte and you must use C@ and C! with it instead of @ and !. Its value is the number base you are currently using, or how many fingers the computer thinks you have. Having set BASE to two, you must type integers in using the penguin notation. (Floating point numbers are different – they are always in base ten except for the exponent part which uses BASE.) The computer will also print the numbers out in penguin.

To get back to human notation, type

1010 BASE C!
because 1010 is penguin for 10. A useful word here, which would have done the same, is DECIMAL: DECIMAL sets BASE to ten. Decimal here means 'based on tens', as in 'decimal coinage', so our notation is a decimal system. The penguin notation, based on twos, is a binary system.

The Jupiter Ace is designed for use by many different species, not just humans and penguins, and you can set BASE accordingly. A three-toed sloth, counting on one foot while it hangs on to a branch with the other three, would set BASE to three; a fork would set BASE to four; and a one-armed bandit would set BASE to five.

Animals wth more than ten fingers have a different sort of problem when they reach ten. Although they've used up our decimal digits, they need some more of their own before they can get on to their 10. The rule is to start using letters, like the sixteen-fingered typist from the moon Ganymede that we employ at Jupiter headquarters. She starts off with our digits 0 to 9, and then uses the letters A to F for ten to fifteen. Only at sixteen does she need to write 10, and then she carries on to 19 (twenty-five), 1A (twenty-six), then to 1F (thirty-one), 20 (thirty-two), and so on. This system, with base sixteen, is called hexadecimal or hex for short.

To summarise them, you need as many digits as you have fingers. If you have more than ten then you'll need not only out usual ten decimal digits, but a few letters as well.

The importance of this lies in the fact that most computers are just like penguins. They store numbers using electrical voltages that can have one of two levels (low=0, high=1), or electronic switches that can be either off (0) or on (1), so they use the penguins' binary system.

This is why powers of two crop up so often with the Ace. A byte, for instance, is a number between 0 and 255, and this is precisely the kind of number that can be written down with just eight bits:

the smallest byte is nought=00000000 in binary.
the biggest is two hundred and fifty-five=11111111 in binary.

How do we work out what a binary number means? In decimal notation the different columns represent different values:

so 255 means two hundreds + five tens + five units.

In binary the same principle applies, except that the columns represent powers of two instead of powers of ten:

Thus in binary, 11111111 means

 Decimal
one * one-hundred and twenty-eight  128
+ one * sixty-four 64
+ one * thirty-two 32
+ one * sixteen 16
+ one * eight 8
+ one * four 4
+ one * two 2
+ one * one 1
two-hundred and fifty-five 255

A quicker way is to imagine adding 1 to it, which will give the binary number 1 0000 0000. The 1 is in the two hundred and fifty-sixes column, so 11111111 is one less than two hundred and fifty-six.

An ordinary integer on the Ace is coded into two bytes or sixteen bits, so on the face of it you'd think integers ranged from 0 to binary 1111 1111 1111 1111 (which is 65535 in decimal – you might remember this as the largest possible address in memory). However, we also need a way of storing negative numbers, so for this we use the rule:

A negative number is stored in the computer with 65536 added to it.

Suppose then our integers are between –32768 and 32767, which is what we said before. 0 and the positive integers, 1 to 32767, are stored just as they are. The negative numbers –32768 to –1 are stored as the numbers 32768 to 65535, so they start where the positive numbers leave off and carry on up to the largest possible number that can be stored in two bytes.

This method of storing negative numbers is known as twos compliment form.

From this we see that two bytes stored in the computer can be interpreted in two different ways: either as a signed number, between –32768 and 32767, or as an unsigned number, ranging between 0 and 65535. Which interpretation we use will often depend on the circumstances.

For instance, you have already seen . which prints out a number. There is also a word U. (standing for 'unsigned dot') which prints out the same number, but interpreted as an unsigned number. If you type in –1 then it is stored as –1+65536=65535 on the stack, but you don't usually notice this, because . decodes it back into the negative number –1. U...

Another word that works on unsigned integers is U< ( integer, integer — flag). This is just like < except for using unsigned integers – try

1 –1 < .
and
1 –1 U< .

U< treats –1 as 65535, which is greater than 1.

Finally, here is a useful shorthand for writing binary numbers: take a number written in binary and separate the bits into groups of 4, starting at the right-hand end. If the leftmost group has less than four bits, then put some 0s in front of it. Next, replace these groups by digits and letters according to this table:

Group of bits  Replace by
00000
00011
00102
00113
01004
01015
01106
01117
10008
10019
1010A
1011B
1100C
1101D
1110E
1111F

For instance, a hundred, which in binary is 110 0100, is replaced by 64.

This handy rule turns out to be exactly the same as writing the number in hex (base 16), and it works because 16=2⁴=2*2*2*2.

Similarly, if you divide the bits into groups of 3 then you end up using octal (base 8) and this too is often used with computers.

Summary

Number base – binary, octal, decimal, hex (hexadecimal)

Signed and unsigned numbers

FORTH words: BASE, DECIMAL, U., U<

Exercises

  1. Why is binary useful when you redesign graphics characters?

  2. Try

    BASE C@ .

    Change the number base, and try again. Why is the number base always 10 however much you change it?

    Write a word .BASE that prints out the number base in decimal. Make sure the number base is the same after .BASE as it was before.

  3. Set the number base to 36. Then the digits to use are the ten decimal digits and the twenty-six letters. Any undefined word with three letters or digits gets stored as a number, so you can say things like

    CAT DOG . .

  4. The rule for negating an integer was to subtract it from 65536. In binary, there is a very easy way of doing this: subtract from 65535 and add 1. This is easy because in binary 65535 is all 1s and subtracting another number from that is the same as changing 0s to 1s and 1s to 0s (1–0=1, 1–1=0).

    This first step is called taking the ones compliment; when you have done the second step of adding 1, you have taken the twos compliment.

  5. If you use hex a lot, define a word

    : HEX
      16 BASE C!
    ;

  6. Work out 2¹⁰ (the answer is 1024). Because this is so close to 1000, it is often used as a kind of binary equivalent of 1000 and is called a K. K here stands for Kilo, because it is a bigger version of the small k in kilometre or kilogram.

    It is very useful for working out approximately how big powers of two are. For instance,

    2¹¹ = 2*2¹⁰ = 2K = about 2000 (actually 2048)
    2²⁰ = 2¹⁰*2¹⁰ = about a million (actually 1048576)