Top: Forth Index Prev: Defining Words Next: Making Decisions

Normal Math Operators

Normal math operators are those which you are very familiar with: addition (+), subtraction (-), multiplication (*) and division (/).

+ ( n1 n2 -- n3 ) Add n1 to n2.

- ( n1 n2 -- n3 ) Subtract n2 from n1.

* ( n1 n2 -- n3 ) Multiply n1 by n2.

/ ( n1 n2 -- quot ) Divide n1 by n2, return the quotient.


New Improved Operators

These operators are commonly used and therefore are predefined for your operating pleasure.

1+ ( n1 -- n2 ) Add 1 to n1.

1- ( n1 -- n2 ) Subract 1 from n1.

2+ ( n1 -- n2 ) Add 2 to n1.

2- ( n1 -- n2 ) Subtract 2 from n1.

2* ( n1 -- n2 ) Multiply 2 by n1.

2/ ( n1 -- quot ) Divides n1 by 2, return the quotient.

They are also provided because they run much faster precompiled than if you ran each seperately. Therefore, 1+ executes much more quickly than 1 +. Of course, you would never know the difference unless you had many iterations of the operator. The following two words compare the speed of execution of the single operator and double operator: (more about the do...loop later)

    ok : test1 1 date 10000000 0 do 1+ loop date ;
    ok test1
    Wed May  3 14:38:13 EDT 1995
    Wed May  3 14:38:20 EDT 1995

    ok : test2 1 date 10000000 0 do 1 + loop date ;
    ok test2
    Wed May  3 14:38:49 EDT 1995
    Wed May  3 14:39:14 EDT 1995
The single operator only took ~7 seconds to add one to a number ten million times. The dual operator version took ~25 seconds, a speed decrease of over 300 percent. (Computations done on a SUN IPX with a SPARC PowerUP chip and CFORTH)


Special Division Operators

Forth provides a few different operators to divide numbers since the default stack (the one we have been using so far, and yes there is more than one stack) only handles integers.

*/ ( n1 n2 n3 -- quot ) n1 times n2, divide by n3, return the quotient.

mod ( n1 n2 -- rem ) n1 divided by n2, return the remainder.

/mod ( n1 n2 -- rem quot ) n1 divided by n2, return the remainder and the quotient.

*/mod ( n1 n2 n3 -- rem quot ) n1 times n2, divide by n3, return the remainder and then the quotient.


Changing Base

Forth, by default, works in base 10, but you can work in binary, hex, octal or any other base you desire. You can also place numbers on the stack of a different base:

    ok 10 .s
    10
    ok h# 10 .s \ Place a hex number on the decimal stack.
    10 16
    ok o# 10 .s \ Place an octal number on the decimal stack.
    10 16 8
    ok b# 10 .s \ Place a binary number on the decimal stack.
    10 16 8 2
    ok hex .s   \ Switch to hex mode.
    a 10 8 2
    ok octal .s \ Switch to octal mode.
    12 20 10 2
    ok binary .s \ Switch to binary mode.
    1010 10000 1000 10
    ok d# 10 .s  \ Place a decimal number on the binary stack.
    1010 10000 1000 10 10
decimal ( -- ) Switch stack to decimal mode.

binary ( -- ) Switch stack to binary mode.

hex ( -- ) Switch stack to hex mode.

octal ( -- ) Switch stack to octal mode.

d# ( "integer" -- n ) Place a decimal number on the stack.

b# ( "integer" -- n ) Place a binary number on the stack.

h# ( "integer" -- n ) Place a hex number on the stack.

o# ( "integer" -- n ) Place an octal number on the stack.

In addition to decimal, octal, hex and binary, you can specify the base you want by changing the value in the base variable:

    ok 10 .s
    10
    ok 3 base ! \ ! is the command to store a number at an address.
                \ More on this later...
    ok .s
    101

Logic

When dealing with binary numbers and flags, it is often useful make comparison tests such as "Are n1 and n2 both positive?" and "Are either n1 or n2 not true?". Also useful when dealing with the control of hardware, you can adjust the actual bits stored at an address. For instance, the fifth bit of a two-byte binary number at the hex address 0x24c might correspond to initializing the board's A/D (analog to digital) converter.

NOTE: A bit is a single boolean number, 1 or 0. A byte is currently defined as 8 bits. One byte can be any number from -128 to 127, 2^8 possible numbers. Our computers are currently 32 bit. The byte is still defined to be 8 bits, but an integer is defined to be 4 bytes long. This gives us a total of 2^32 possible 4-byte integers: 4,294,967,296! The range of numbers supported is -2,147,483,648...2,147,483,647. In binary, though, the range of numbers is 11111111111111111111111111111111 to 01111111111111111111111111111111 (32 ones to 31 ones). The one on the far left is called the Most Significant Bit because it determines whether the number is positive or negative. Let's look at a number line in binary, decimal and hex (base 16):

    BINARY (actual representation)         DECIMAL         HEX
    
    11111111111111111111111111111111        -1              -1
    ...
    10000000000000000000000000000000        -2,147,483,648  -80000000
    01111111111111111111111111111111         2,147,483,647   7fffffff
    ...
    00000000000000000000000000000001         1               1
    00000000000000000000000000000000         0               0
I say that the binary column is an actual representation because CFORTH will report -1 in decimal as -1 in binary, -10 in decimal as -1010 in binary. You can see which method is easier to read and compute.

Examples of binary arithmetic (the top row is the decimal representation of the corresponding binary statements underneath):

    10 AND 13       10 OR 13        10 XOR 13       10 NOT

    1010            1010            1010
    1101 and        1101 or         1101 xor        1000 not
    --------        -------         --------        --------
    1000 == 8       1111 == 15      0111 == 7       -0111 == -9
So what's going on here? The AND example shows that both bits need to be true for the result to be true. Any other combination ( 1 0, 0 1, 0 0) yields a false value. The OR example shows that any combination of 1 and 0 yields a true value and only a pair of zeroes returns false. The third example, XOR, shows that for any non-zero pair, the answer is true. You can always add a zero to the front of a binary number without its value changing. So, 01010 01101 xor = 01111.

The last example, NOT, is a bit peculiar. Instead of returning a true or false answer, it returns one's complement, the equivalent of subtracting each bit from one. This means that all bits are changed from zero to one or one to zero. This includes the bit which determines whether a number is positive or negative, usually referred to as the most significant bit (MSB). In order to determine whether a number is true or false, you should use 0= as mentioned above.

Let's say that we have a binary number,1000010000110100, which refers to the current state of an A/D converter. We would like to change the third bit (2^2) to a 0 (i.e. turn off that bit). This would be done by taking a binary number which corresponds to just that third bit being on, 0000000000000100, finding its one's complement and then anding them together. To turn bit 3 on again, simply take the binary number representing the current state and or it to a binary number with only the third bit true.

    OFF:                            ON:

         0000000000000100 not           1000010000110000
        ---------------------                        100 or
        -1111111111111011               -------------------
                                        1000010000110100
        -1111111111111011
         1000010000110100 and
        ---------------------
         1000010000110000
and ( n1 n2 -- n3 ) Logical and.

or ( n1 n2 -- n3 ) Logical or.

xor ( n1 n2 -- n3 ) Exclusive or.

not ( n1 -- n2 ) One's complement: for positive numbers subtract n1 from -1, for negative numbers add to -1.


Top: Forth Index Prev: Defining Words Next: Making Decisions