For the things we have to learn before we can do them, we learn
by doing them.
Aristotle
STRENGTH IN FORTH
part two
THE GREEK CONNECTION
Last time I left you on the stack, with nothing to do. But we did
some arithmetic, remember ? We solved 3 5 + . This time we are
going to do some more of that. (That's why I would have left you
on the stack anyway !). In FORTH arithmetic is a matter of to
stack or not to stack....and numbers of course. It is therefore
essential to study thoroughly the stack's magic and FORTH's
numbers.
NUMBER & BUMPER
Now for the numbers. If you aren't acquainted with the basic (sic
!) ins and outs of binary and hexadecimal representation of
numbers both inside and outside a computer, I suggest you to buy
a book on that stuff. It would be tiresome to get through all
that here and now. So I assume at least you know enough, to
understand the following explication.
A computer does it in binary; all ones and nulls. Thus,
computer's maths are in binary as well. Numbers are stored in
binary. To store numbers you need some place to store them:
locations, memorylocations. A computer can find each
location by its address.
The smallest piece of memory used to store numbers is called a
byte. (Of course you may write, if you think you know better; but
it will cost you a life-time working to pay the back-postage ).
A byte consists of 8 bits. Each bit can have the value of either
1 or 0. If you should write down all possible combinations of 0's
and 1's that fit into a byte, you would have a collection of 256
numbers, ranging from 0 to 255 inclusive.
THE GREAT DECEPTION
Meanwhile, did you notice that a bit can be 0 or 1, i.e positive
(= 1), or not-positive (= 0), but NOT NEGATIVE. Handling positive
numbers may well be a natural way-of-life for a computer. To
handle negative numbers, we need to mislead the computer. We can
deceive it by the two's- complement arithmetrick. Now, FORTH is
16-bit oriented. In unsigned 16-bit arithmetic the lowest number
you might represent is zero. In binary: 0000000000000000. And the
highest appears in binary as 1111111111111111, which is 65535 in
decimal. In this constellation there are 65536 numbers. Now watch
the trick !! Consider what happens, if I add 1 to the highest
number(65535).
1111111111111111
+ 0000000000000001
(1)0000000000000000
As I have only 16 bits, the 1 in the 17th place is lost. The
remaining 16 bits are stored as the value zero. IF WE ADD A 1 TO
A NUMBER AND THE RESULT IS 0, WE THEN CAN EASILY INTERPRET THE
ORIGINAL NUMBER (I.E. 1111111111111111) AS THE VALUE -1. In this
way the computer is mislead to think 16 positive bits is -1. So,
if 16 bits are positive (= TRUE), a number is interpreted as -1.
Now it will be clear to you, why in computerlogic TRUE is -1;
because all bits are TRUE ! Keep that in mind: 16-bit numbers can
be thought of as either signed or unsigned numbers. Signed
numbers range from -32768 up to 32767. Unsigned numbers range
from 0 up to 65535. All numbers are integers.
To learn how to ride on horseback, you have to sit on...and ride.
To use FORTH, you need to know how it works, to know how it works
you need to use FORTH. We are going to use FORTH, to see if we
were right about FORTH's numberhandling.
Just enter: -1 {DUP} {.} {U.} -1 65535OK. Let's trace back and
see what happened.
1. -1 TOS 2. DUP (means duplicate value TOS) 3. . (outputs the
number TOS) 4. U. (outputs the number TOS).
The stack shows: -1
-1
Now {.} removes the value TOS and prints it as a signed number.
The stack shows: -1
{U.} removes the value TOS and prints it as a unsigned number.
That's where the U stands for: Unsigned.
For further elucidations on this subject we need to examine the
binary form of -1 and 65535. We can (I can, you can't) achieve
our goal by making a new word by defining a colondefinition. The
name 'colondefinition' is quite obvious. The first character is a
colon. Here it is. : B. BASE C@ 2 BASE C! SWAP U. BASE C! ;
OK.
As a colon is a FORTH-word, seperate it by a space from other
words. Semi-colon always ends a colondefinition. Perhaps you
didn't realize, but all numbers till now were output in decimal
base, FORTH's default base. You can easily change that base,
simply by storing a new basevalue in the word {BASE}. In the word
{B.} that was done through the sequence ..2 BASE C!..
Do it now. 2 {BASE} C! OK. Now FORTH is in binary base. Again,
changing to octal base. 1000 {BASE} C! OK. Why on earth 1000 ?
Because we were in binary and 1000 is eight in binary. Back to
decimal again. Well said, but how to type ten in octal ? Believe
me, it is 12. So 12 {BASE} C! OK. The rest of {B.} is set up to
return to decimal from binary. There is one word of interest:
{SWAP}. {SWAP} exchanges the two top stack values. Type 3 5 OK.
The stack shows: 5
3
Type {SWAP} OK. Type {.} 3OK. It is not much like {.} to
print out the second top stack item, so {SWAP} must have
exchanged our two little numbers, 5 becoming second and 3
becoming TOS. Let's try {B.} (say bee-dot). (One rainy day I will
teach how to define a Dolly-Dot-word, you bet.)
Type -1 {DUP} {B.} {.} 1111111111111111 -1OK. Type 65535 {DUP}
{B.} {U.} 1111111111111111 65535OK.
See, in binary there isn't any difference between -1 and 65535.
It is {.} and {U.} that makes a different OUTPUT.
And my Greek connection Aristotle proved he was right in what he
was saying about learning things by doing them.
With {B.} you may examine in which way FORTH stores 16-bit
numbers internally. With {.} and {U.} you may have a look at
their signed and unsigned visual shapes. (If you own a non-83-
standard FORTH, it may be that the stackwidth is not 16-bit, but
32-bit. All what was said and all what is to be said about 16-bit
applies equally for the numbers and operators designed for a 32-
bit stack. We'll make further remarks on 32-bit stacks in part 3)
Most arithmetic in FORTH is very simple. Because you always deal
with integers of a fixed range. FORTH supplies sufficient
operators to do all sorts of maths. Sometimes you will have to
write an operator yourself. I will give examples in this course .
There is still more to tell about numbers. But for now the
subject is closed. We will examine the operators. All operators
to be spoken of in the next few lines, work on 16-bits integers
only. Sixteen-bit numbers are referred to as single-length or
single-precision numbers. I prefer single-length: short s.l. So
we discuss s.l.-operators.
FAMILYPORTRAIT
We've met one member of the clan, {+}. You already know him, so
say hello. Let's proceed with {-} (say: minus). Minus acts
similar to the tax-official, it subtracts. It takes the two
numbers TOS, subtracts and places the result back TOS. Type 345
344 {-} {.}
1OK. Mind, the number to be subtracted must be highest on the
stack.
Next to Minus is {*} (say: star). Star's job is to multiply the
two numbers highest on the stack and place the product back. Pay
special attention to Star, because it is likely to produce large
numbers, which may exceed the 16-bit range. Type 37 3 {*} {.}
111OK.
The fourth clanmember is {/} (say: slash). Slash was born to
divide, so he does. Whithout compassion: nothing remains.
Enter e.g. 83 4 {/} {.} 20OK. The remainder (3) is lost.
Slash' twin brother is {MOD} (say: mod). Mod ignores the quotient
and saves the remainder only. So 83 4 {MOD} {.} 3OK.
The combination of Slash and Mod gives you and a quotient and a
remainder. It is written as {/MOD} and pronounced slashmod. Enter
83 4 {/MOD} {.} {.} 20 3OK . The result is not 20.3 or the
like, as {/MOD} puts the quotient and the remainder as two 16-bit
numbers on the stack.
Star and Slash both have a specialised nephew {2*} and {2/} (say:
twostar - twoslash). These are very fast operators. As dividing
and multiplying by two are most common in use, FORTH's demand for
speed is due to their birth. Mind the difference between 2 {*}
and {2*}, as in writing (space), as well as in speed.
STARSLASH, THE MENACE
Some lines ago I warned you when you use {*}, to be careful to
stay within the sixteen-bit range. Now here I present you the
menace of the clan. The next operator isn't quite loyal to the
Sixteenbitclan. It has a miscellaneous character. You write it as
{*/} and pronounce it as starslash. This is how it acts. Enter
please 113 768 {*} 8 {/} {.} and that's not the right answer.
Now enter 113 768 8 {*/} {.} 10973OK. And that's right. What
happened ? In the first example the result of 113 768 {*} didn't
fit into 16 bits (113 x 768 = 87784). In the second example the
result of the multiplication-part of the operator {*/} is as long
as 32 bits ! This intermediate result is then divided by 8 and
the final result is put TOS as a s.l.-number. (In 32 bits signed
numbers can range from -2147483648 to +2147483647 inclusive.)
The input on the stack for use by {*/} is always the two numbers
to be multiplied first, followed by the divider.
Starslash does not supply a remainder, as does {*/MOD}. The
latter gives you everything: speed, 32-bits intermediate result,
quotient and remainder. I will discuss more fundamental aspects
of these two words together with the subject of floating-point
and scaling.
The family-portrait of our Sixteenbitters shows still some
unknown faces. Here are {NEGATE} and {ABS}. They both perform
exactly that kind of action, you expect them to do from their
name. {NEGATE} changes the sign of a number, {ABS} returns the
absolute value of a number. E.g. 18 {NEGATE} {.} -18OK -18
{NEGATE} {.} 18OK; .
-18 {ABS} {.} 18OK 18 {ABS} {.} 18OK. Look carefully at the
output of the examples. Two pairs of words seem to be
superfluous: {1-} {1+} and {2-} {2+}. You may look upon them in
the same way as {2*} and {2/}. They perform very common
stackactions and as putting numbers on the stack is somewhat
slowing down FORTH's speed (He thinks, though), these words are
especially designed for speed. So 1 {+} is slower than {1+}. Not
noticeable when the plussing is done one time, but the time-
saving aspect of {1+} becomes substantial if the operation has to
be carried out thousands and thousands of times.
UNSPOKEN
I owe you some explanation. I didn't want to disturb the
procedure of what was to be explained about 16-bit numbers too
much, so two words were unspoken off: {C@} and {C!} in the
definition of {B.}.
For now this will do. {C@} extracts a byte value from the word
{BASE} and put that value TOS. Which value depends on the
numberbase FORTH is working in: a 2 in binary, a 10 in decimal, a
16 in hexadecimal base. {C!} is the opposite of {C@}: it stores a
byte-value into a word. So 5 {BASE} {C!} will put the value of 5
into the word {BASE}. The value has to be TOS.
I invited you to define the word {B.}. If you accepted my
invitation the definition was put in the dictionary. But....if
you disconnect the powersupply or reset your machine you'll
have to reload FORTH. You will then discover, that our {B.}-word
has disappeared from the dictionary. If you want it back, you'll
have to define it anew. There is of course a way to preserve
self-defined words on disc. Wait for the editor to be
explained.......
Next time we will discuss the stack's magic. Two spells I gave
already: {DUP} and {SWAP}. But there are some more. And we will
have a look at FORTH relational and logical operators too....and
seeing things double right now ? We will discuss double-length
arithmetic as well. Keep smiling !!
SUMMARY
FORTH's arithmetic takes place on the stack. FORTH supplies a
lot of arithmetic operators with specific functions. Numbers are
16-bits (or 32-bits) long and integer. Single-length or single-
precision arithmetic deals with 16-bits numbers. The s.l.
arithmetic operators are designed to work on s.l. numbers
exclusively: a list is provided in this part two. In s.l.
arithmetic signed numbers range from -32768 to +32767 inclusive.
In unsigned form s.l. numbers range from 0 to 65535 inclusive.
Exceeding these limits will give unreliable results. All signed
numbers are in two's complement form.
On 32-bit stacks there is no distinction between single- and
double-length numbers. REMEMBER
Two's complement - The two's complement of a number is the
exact equal absolute value but with opposite
sign.
Integer - An integer is a number with no fractional
parts. E.g. 123, 2, -365 are integers.
Numberbase - A number is a complex symbol. In daily life
we use decimal base. Ten is the base. To
compose a number there are two main points
to observe: the value of a figure, and the
place of that figure in the number. The
place is calculated from right (=0) to
left. An example. Number 23456. The 6 has
a value of six and place 0. The decimal
value of 6 is now 6 * 10^0. Now 10^0=1. So
the 6 in place 0 is worth six. As for the
5. The decimal value of the 5 is 5 * 10^1=
5*10=50. The 4: 4*10^2=4*100=400, the 3:
3*10^3=3*1000=3000. In place 0 the
basenumber is raised to the power of 0, in
place 1 to the power of 1, in place 2 to
the power of 2 etc. etc. When you choose
another base, the one thing to change in
the example above is the 10.
E.g. we choose base 8, octal base. The 6
is 6*8^0=6*1=6. The 5: 5*8^1=5*8=40. The
4: 4*8^2=4*64=256 etc. etc. You may change
to whatever base you like, the calculation
remains the same. The most common bases
used are decimal, binary and hexadecimal.
Dolly Dots - A worldfamous (in Holland, though) female
popgroup.
Colondefinition - A colondefinition is the most common way of
defining new words. The word {:} always
opens the definition, followed by a space and
the name of the new word. Then other words
follow to define the action of the new word.
The last word always is {;}.
Aristotle - Greek philosofer (4th cent. b.C.). The quotation is
to be found in 'Nicomachean Ethics'.
_________________________________________________________________
| word | stackaction | description |
|¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
| + | (n1\n2 -- sum: n1+n2) | Add |
| - | (n1\n2 -- dif: n1-n2) | Subtract |
| * | (n1\n2 -- prd: n1*n2) | Multiply |
| / | (n1\n2 -- quo: n1/n2) | Divide (integer) |
| MOD | (n1\n2 -- remainder ) | Remainder of n1/n2 |
| /MOD | (n1\n2 -- rem\quo ) | Leave quotient with |
| | | remainder beneath |
| */ | (n1\n2\n3 -- n1*n2/n3) | Intermediate product n1*n2|
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
_________________________________________________________________
| word | stacknotation | description |
|¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
| | | is stored as 32-bit number|
| */MOD |(n1\n2\n3 -- rem\n1*n2/n3)| As */ but also leaves |
| | | remainder beneath |
| NEGATE | (n1 -- -n1) | Change sign |
| ABS | (n1 -- |n1|) | Absolute value |
| 1+ | (n1 -- n2) | Add 1 to top stack item |
| 1- | (n1 -- n2) | Subtract 1 from top stack |
| | | item |
| 2+ | (n1 -- n2) | Add 2 to top stack item |
| 2- | (n1 -- n2) | Subtract 2 from top stack |
| | | item |
| 2* | (n1 -- n2) | Fast multiply by 2 |
| 2/ | (n1 -- n2) | Fast divide by 2 |
|________|__________________________|___________________________|
EXTRAS
A very popular word in FORTH is FIG. Although it is a FORTH-word
you never will encounter it in a dictionary. It stands for FORTH
Interest Group. This group exists to promote interest in and use
of FORTH. The parent-group is found in the USA; but almost each
country has its own branch. Enquire your computerclub for
addresses. I give you only the USA-address:
FORTH Interest Group
PO Box 1105
San Carlos
Ca 94070
U.S.A.
And if you write, please enclose a Self Addressed Stamped
Envelope (SAE)!!
EXERCISES
1. Put (as many as you like) negative numbers on the stack.
Have them output by {B.}. Be sure {B.} is in the dictionary.
Mark the state of the 16th bit.
Clear the stack with help of {SP!}. Repeat, but this time
with positive numbers. Again, mark the state of the 16th bit.
What can you tell now about signed numbers regarding the 16th
bit ? Explain why that bit is called the sign-bit !
2. Remember Starslash ? On that subject I gave an example that
turned out to give false answers: 113 768 {*} 8 {/}. Rewrite
this example to give the right answer, not using {*/}.
3. Rewrite this formula:344 X 105 in R.P.N. in two ways.
35
4. What is the remainder of: 576 X 861
15
5. What is the unsigned equivalent of -986 ?
6. Write the next formula down in such a way, that all operands
are on one side and the operators on the other side:
(69 + 3) X 5 e.g. 1480 5 3 97 * + /
18
7. {*/MOD} has two 16-bit numbers put on the stack, a quotient
and a remainder. Which of them two is the higher on the
stack?
Use your brains, not the stacknotation !
8. Subtract: 8 - 4, but don't use {-}. 9. Explain the following
stacknotation: (n -- n^2). Here is the word, I wrote. : QUAD
DUP * ;.
10. Write your own word of which the stacknotation is (n -- n^3).
Next time I'll give the solutions. Till then !!!
Disclaimer
The text of the articles is identical to the originals like they appeared
in old ST NEWS issues. Please take into consideration that the author(s)
was (were) a lot younger and less responsible back then. So bad jokes,
bad English, youthful arrogance, insults, bravura, over-crediting and
tastelessness should be taken with at least a grain of salt. Any contact
and/or payment information, as well as deadlines/release dates of any
kind should be regarded as outdated. Due to the fact that these pages are
not actually contained in an Atari executable here, references to scroll
texts, featured demo screens and hidden articles may also be irrelevant.