Excerpts from Forth Programmer's Handbook #2
Forth offers a comprehensive set of commands for performing arithmetic and logical functions. The functions in a standard system are optimised for integer arithmetic, because not all processors have hardware floatingpoint capability and software floating point is too slow for most realtime applications. All Forth systems provide words to perform fast, precise, scaledinteger computations; many provide fixedpoint fraction computations, as well. On systems with hardware floatingpoint capability, many implementations include an optional, complete set of floatingpoint operations, including an assembler. See Section 3.11 in this manual and the product documentation for these systems for details.
Programmers who are new to Forth should review Starting Forth's comprehensive discussion of Forth's handling of numbers and arithmetic.
2.2.1 Arithmetic and Shift Operators
In order to achieve maximum performance, each version of Forth implements most arithmetic primitives to use the internal
behaviour of that particular processor's hardware multiply and divide instructions. Therefore, to find out at the bit level what these primitives do, you should consult either the manufacturer's hardware description or the implementation's detailed description of these functions.
In particular, signed integer division  where only one operand (either dividend or divisor) is negative and there is a remainder  may produce different, but equally valid, results on different implementations. The two possibilities are floored and symmetric division. In floored division, the remainder carries the sign of the divisor and the quotient is rounded to its arithmetic floor (towards negative infinity). In symmetric division, the remainder carries the sign of the dividend and the quotient is rounded towards zero, or truncated. For example, dividing 10 by 7 can give a quotient of 2 and remainder of 4 (floored), or a quotient of 1 and remainder of 3 (symmetric).
Most hardware multiply and divide instructions are symmetric, so floored division operations are likely to be slower. However, some applications (such as graphics) require floored division in order to get a continuous function through zero. Consult your system's documentation to learn its
behaviour.
The following general guidelines may help you use these arithmetic operators:

The order of arguments to orderdependent operators (e.g.,
 and / ) is such that, if the operator were moved to an infix position, it would algebraically describe the result. Some examples:
Forth 
Algebraic 
a b  
a  b 
a b / 
a / b 
a b c */ 
a * b / c 
 All arithmetic words starting with the letter
U are unsigned; others are normally signed. The exception to this rule is that, on most systems, M*/ requires a positive divisor.
 When executing operations involving address calculations, use the words
CELL+ , CELLS , CHAR+ , and CHARS as appropriate to convert logical values to bytes, rather than to absolute numbers. For example, to increment an address by three cells on a 32bit system, use 3 CELLS + , not 12 + ; this makes the code portable to systems that may have different cell widths.
These operators perform arithmetic and logical functions on numbers that are on the stack. In general, the operands are removed (popped) from the stack and the results are left on the stack.
Glossary 
SinglePrecision Operations 

* ( n1 n2  n3 )
Multiply n1 by n2 leaving the product n3. "star" 

*/ ( n1 n2 n3  n4 )
Multiply n1 by n2, producing an intermediate doublecell result d. Divide d by n3, giving the singlecell quotient n4. "starslash" 

*/MOD ( n1 n2 n3  n4 n5 )
Multiply n1 by n2, producing intermediate doublecell result d. Divide d by n3, giving singlecell remainder n4 and singlecell quotient n5. "starslashmod" 

+ ( n1 n2  n3 )
Add n1 to n2, leaving the sum n3. "plus" 

 ( n1 n2  n3 )
Subtract n2 from n1, leaving the difference n3. "minus" 

/ ( n1 n2  n3 )
Divide n1 by n2, leaving the quotient n3. See the discussion at the beginning of this section about floored and symmetric division. "slash" 

/MOD ( n1 n2  n3 n4 )
Divide n1 by n2, leaving the remainder n3 and the quotient n4. "slashmod" 

1+ ( n1  n2 )
Add one to n1, leaving n2. "oneplus" 

1 ( n1  n2 )
Subtract one from n1, leaving n2. "oneminus" 

2+ ( n1  n2 )
Add two to n1, leaving n2. "twoplus" 

2 ( n1  n2 )
Subtract two from n1, leaving n2. "twominus" 

2* ( x1  x2 )
Return x2, the result of shifting x1 one bit toward the mostsignificant bit, filling the leastsignificant bit with zero (same as 1 LSHIFT ). "twostar" 

2/ ( x1  x2 )
Return x2, the result of shifting x1 one bit towards the leastsignificant bit, leaving the mostsignificant bit unchanged. "twoslash" 

CELL+ ( aaddr1  aaddr2 )
Add the size in bytes of a cell to aaddr1, giving aaddr2. Equivalent to 2+ on a 16bit system and to 4 + on a 32bit system. "cellplus" 

CELLS ( n1  n2 )
Return n2, the size in bytes of n1 cells. 

CHAR+ ( caddr1  caddr2 )
Add the size in bytes of a character to caddr1, giving caddr2. "careplus" 

CHARS ( n1  n2 )
Return n2, the size in bytes of n1 characters. On many systems, this word is a noop. "cares" 

LSHIFT ( x1 u  x2 )
Perform a logical left shift of u places on x1, giving x2. Fill the vacated leastsignificant bits with zeroes. "Lshift" 

MOD ( n1 n2  n3 )
Divide n1 by n2, giving the remainder n3. 

RSHIFT ( x1 u  x2 )
Perform a logical right shift of u places on x1, giving x2. Fill the vacated mostsignificant bits with zeroes. "Rshift" 

DoublePrecision Operations 

D+ ( d1 d2  d3 )
Add d1 to d2, leaving the sum d3. "Dplus" 

D ( d1 d2  d3 )
Subtract d2 from d1, leaving the difference d3. "Dminus" 

D2* ( xd1  xd2 )
Return xd2, the result of shifting xd1 one bit toward the mostsignificant bit and filling the leastsignificant bit with zero. "Dtwostar" 

D2/ ( xd1  xd2 )
Return xd2, the result of shifting xd1 one bit towards the leastsignificant bit and leaving the mostsignificant bit unchanged. "Dtwoslash" 

MixedPrecision Operations 

D>S ( d  n )
Convert doubleprecision number d to the singleprecision equivalent n. Results are undefined if d is outside the range of a signed singlecell number. "DtoS" 

FM/MOD ( d n1  n2 n3 )
Divide d by n1, using floored division, giving quotient n3 and remainder n2. All arguments are signed. This word and SM/REM will produce different results on the same data when exactly one argument is negative and there is a remainder. "FMslashmod" 

M* ( n1 n2  d )
Multiply n1 by n2, leaving the doubleprecision result d. "Mstar" 

M*/ ( d1 n1 +n2  d2 )
Multiply d1 by n1, producing a triplecell intermediate result t. Divide t by the positive number n2 giving the doublecell quotient d2. If doubleprecision multiplication or division only is needed, this word may be used with either n1 or n2 set equal to 1. "Mstarslash" 

M+ ( d1 n  d2 )
Add n to d1, leaving the sum d2. "Mplus" 

M ( d1 n  d2 )
Subtract n from d1, leaving the difference d2. "Mminus" 

M/ ( d n1  n2 )
Divide d by n1, leaving the singleprecision quotient n2. This word does not perform an overflow check. "Mslash" 

S>D ( n  d )
Convert a singleprecision number n to its doubleprecision equivalent d with the same numerical value. "StoD" 

SM/REM ( d n1  n2 n3 )
Divide d by n1, using symmetric division, giving quotient n3 and remainder n2. All arguments are signed. This word and FM/MOD will produce different results on the same data when exactly one argument is negative and there is a remainder. "SMslashrem" 

T* ( d n  t )
Multiply d by n, yielding a tripleprecision result t. Used in M*/ . "Tstar" 

T/ ( t +n  d )
Divide a tripleprecision number t by the positive number +n, leaving a doubleprecision result d. Used in M*/ . "Tslash" 

UM/MOD ( ud u1  u2 u3 )
Divide ud by u1, leaving remainder u2 and quotient u3. This operation is called UM/MOD because it assumes the arguments are unsigned, and it produces unsigned results. Compare with SM/REM and FM/MOD . "UMslashmod" 

UM* ( u1 u2  ud )
Multiply u1 by u2, leaving the doubleprecision result ud. All values and arithmetic are unsigned. "UMstar" 
2.2.2 Logical and Relational Operations
As in the case of arithmetic operations, Forth's implementation of logical and relational operations optimises speed and simplicity. This does imply some limitation on generality in 16bit systems, although this limitation rarely is an issue in realtime applications.
In order to fully understand the issues, we can represent the entire set of 16bit integers in three ways, as shown in Figure 7.
A relational which treats a given 16bit integer as a point on the full signed number line (a) is needed for true arithmetic or algebraic numbers in which the application has carefully determined that there will never be overflow or underflow. For example, this type of relational is needed to test whether 20,000 is less than +20,000. A relational which treats all values as unsigned (b) is also needed, primarily to test locations of given addresses.
Figure 7. Three ways of representing 16bit binary numbers
The number line, or rather number circle, shown in (c) probably needs more explanation than the other two. Relational operators which treat numbers in this way have the advantage of being able to act like signed tests around zero and like unsigned tests around 32K. Thus the relation between two numbers is totally independent of their absolute position on the number circle.
It may seem that the third case is the rarest and least useful. In fact, though, it turns out that it handles the vast majority of signed comparisons in real applications and, better still, it is much faster in execution and easier to implement than a relational that assumes number line (a).
Consider three points on the number circle, as shown in Figure 8. It doesn't matter where these points lie in relation to true zero on the circle. Since numbers increase in a clockwise direction, point A is considered to be greater than point X. Point B is considered to be less than point X. Notice that the maximum range of comparisons in the circle is 32K. Further away than that, a value will appear to lie in the opposite semicircle and will produce the opposite result.
Figure 8. A circular representation of the range of 16bit numbers
Thus, a relational which uses this number circle is limited to a 32K range for any single test. Since most comparisons use an extremely small fraction of the total 64K range of the circle, this limitation is generally safe.
The number circle relational is easy to implement because it can be defined in terms of subtract, e.g.,
: <  0< ;
When A is subtracted from X, the arc of the difference is greater than 180 degrees. That is to say, the result of subtraction will appear to be negative in sign. When B is subtracted from X, the arc of the difference is less than 180 degrees; this difference will appear positive. In the first case, the 0< test produces true, in the second case false.
16bit versions of Forth use the fully signed model (option a in Figure 7) to implement most relationals, as well as MAX and MIN . 32bit versions of Forth use the circular model. The operator U< is provided for unsigned comparisons, particularly for 16bit memory addresses that can extend over the full 0  64K range.
Glossary 
SinglePrecision Logical Operations 

ABS ( n  +n )
Replace the top stack item with its absolute value. 

AND ( x1 x2  x3 )
Return x3, the bitbybit logical and of x1 with x2. 

INVERT ( x1  x2 )
Invert all bits of x1, giving its logical inverse x2. 

MAX ( n1 n2  n3 )
Return n3, the greater of n1 and n2. 

MIN ( n1 n2  n3 )
Return n3, the lesser of n1 and n2. 

NEGATE ( n  n )
Change the sign of the top stack value; if the value was negative, it becomes positive. The phrase NEGATE 1 is equivalent to INVERT (1's complement of the input value). 

OR ( x1 x2  x3 )
Return x3, the bitbybit inclusive or of x1 with x2. 

XOR ( x1 x2  x3 )
Return x3, the bitbybit exclusive or of x1 with x2. The phrase 1 XOR is equivalent to INVERT (1's complement of the input value). 

DoublePrecision Logical Operations 

DABS ( d  +d )
Return the absolute value of a doubleprecision stack value. 

DMAX ( d1 d2  d3 )
Return d3, the larger of d1 and d2. 

DMIN ( d1 d2  d3 )
Return d3, the lesser of d1 and d2. 

DNEGATE ( d  d )
Change the sign of a doubleprecision stack value. Analogous to NEGATE . 
2.2.3 Comparison and Testing Operations
These operations leave on the stack a number that is based upon a test of the contents of one or more items on top of the stack. In general, the test is destructive, in that it replaces the item(s) tested with the numerical results of the test. All numbers in Forth may be interpreted as true or false values; zero equals false, and any nonzero value equals true. The words below, which perform explicit tests, return 1 for true. Comparison and testing operations generally precede an IF , WHILE , or UNTIL construct.
You may also use  (minus) or D as a notequal test, because they return a nonzero difference if the two single or doubleprecision numbers are unequal.
Glossary 
0< ( n  flag )
Return flag, which is true if and only if n is less than zero. "zerolessthan" 

0<> ( n  flag )
Return flag, which is true if and only if n is not equal to zero. "zeronotequal" 

0= ( n  flag )
Return flag, which is true if and only if n is equal to zero. "zeroequal" 

0> ( n  flag )
Return flag, which is true if and only if n is greater than zero. "zerogreaterthan" 

< ( n1 n2  flag )
Return flag, which is true if and only if n1 is less than n2. "lessthan" 

<> ( n1 n2  flag )
Return flag, which is true if and only if n1 is not equal to n2. "notequal" 

= ( n1 n2  flag )
Return flag, which is true if and only if n1 is equal to n2. "equal" 

> ( n1 n2  flag )
Return flag, which is true if and only if n1 is greater than n2. "greaterthan" 

D0< ( d  flag )
Return flag, which is true if and only if the doubleprecision value d is less than zero. "dzeroless" 

D0= ( d  flag )
Return flag, which is true if and only if the doubleprecision value d is equal to zero. "dzeroequal" 

D< ( d1 d2  flag )
Return flag, which is true if and only if d1 is less than d2. "dlessthan" 

D= ( d1 d2  flag )
Return flag, which is true if and only if d1 is equal to d2. "dequals" 

DU< ( ud1 ud2  flag )
Return flag, which is true if and only if ud1 is less than ud2. "duless" 

FALSE (  flag )
Return a flag that is false (binary zero). 

NOT ( flag1  flag2 )
Identical to 0= , used for program clarity to reverse the results of a previous test. For example, the following code would test for a value greater than or equal to zero: 0< NOT 

TRUE (  flag )
Return a flag that is true (singlecell value with all bits set). 

U< ( u1 u2  flag )
Return flag, which is true if and only if u1 is less than u2. "ulessthan" 

U> ( u1 u2  flag )
Return flag, which is true if and only if u1 is greater than u2. "ugreaterthan" 
References 
Conditionals, Section 2.5.3 

MAX and MIN , Section 2.2.2 

Posttesting loops, Section 2.5.2 

Pretesting loops, Section 2.5.1 

String comparisons, Section 2.3.4 
Back to Forth Programming Handbook Index
Back to COMSOL's Forth products page
(Online excerpt from broader discussion of Defining Words)
One of the most powerful capabilities in Forth is the ability to define new defining words. Thus, the programmer may create new data types with characteristics peculiar to the application, new generic types of words, and even new classes of words with a specified behavior that is common to each class.
In creating a custom defining word, the programmer must specify two separate behaviours:
 The compiletime behavior of the defining word (creating the dictionary entry, compiling parameters, etc.).
 The runtime behavior (the action to be performed by words created by the new defining word).
In the cases discussed in the next two sections, compiletime behavior is described in highlevel Forth. Several methods for specifying runtime behavior are also discussed.
2.7.6.1 Basic Principles of Defining Words
There are two ways to create new defining words in Forth. In the one case (using DOES> ), the runtime behavior is described in highlevel Forth; in the other (using ;CODE ), the runtime behavior is described in assembler code. The basic principles are the same.
In Forth, a defining word will create a new dictionary entry when executed. All words defined by the same defining word share a common compiletime and runtime behavior. For example, VARIABLE is a defining word; all words defined by VARIABLE share two common characteristics:
 Each has one cell allotted in which a value may be stored. These bytes may be initialised to zero in some systems.
 When executed, each of these words will push onto the stack the address of this onecell reserved area.
On the other hand, all words defined by CONSTANT , which is another defining word, share two other behaviours:
 Each has compiled into its parameter field a singleprecision value, which was on the stack when
CONSTANT was executed.
 When a word defined by
CONSTANT executes, it puts its value on the stack.
In each of these examples, the first behavior (the compiletime action) relates to the physical construction of the word, which is determined when the word is compiled. The second behavior describes what all defined words of that type do when executed. All defining words must have a compiletime behavior and a runtime behavior.
The general definition of a defining word looks like:
:<name> <compiletime behavior> <transition word>
<runtime behavior> ;
The transition word ends the specification of compiletime behavior and begins the specification of runtime behavior. There are two such transition words: ;CODE , which begins runtime behavior described in code (assembler); and DOES> , which begins runtime behavior described in highlevel Forth.
The exact behavior of these two words is discussed in the following sections. The description of compiletime behavior is the same, regardless of which transition word is used. In fact, if you change the transition word and runtime behavior from DOES> plus highlevel to ;CODE plus equivalent code, no change to the compiletime behavior is necessary.
The compiletime portion of a defining word must contain an existing defining word to create the dictionary entry. If one or more parameters are to be compiled, or if space for variable data is to be allocated, it is convenient to use a defining word which takes care of that for you. The most common defining words, all of which have been described in previous sections, are: CREATE , CONSTANT , 2CONSTANT , VARIABLE , and 2VARIABLE . CREATE is used when there are no compiletime parameters or when space is to be allocated with ALLOT . CONSTANT and VARIABLE reserve space for one parameter; 2CONSTANT and 2VARIABLE reserve space for a doublecell number or two singlecell parameters.
Every defining word must provide space for data or code belonging to each instance of the new class of words. For example, when a variable is defined, space is allotted for its parameter field. If more space is needed than a standard word (e.g., VARIABLE or 2VARIABLE ) allots, the usual approach is to use CREATE followed by ALLOT but, if the application is to be targetcompiled for ROM, VARIABLE and ALLOT must be used (see Section 2.7.1).
After a new defining word has been created, it can be used to create specific instances of its class, with the syntax:
<parameters> <defining word> <instance1>
<parameters> <defining word> <instance2>
and so forth. The instance1 and instance2 are names that would be specified in an application. The parameters are optional, depending on the defining word, and are specific to each instance.
When a defining word is executed, it may be followed by any number of words  such as , (to compile a singleprecision value) or C, (to compile an 8bit value) to fill the allotted storage area with explicit values.
Glossary 
;CODE (  )
Begin runtime behavior, specified in assembly code. "semicoloncode" 

DOES> (  )
Begin runtime behavior, specified in highlevel Forth. At run time, the address of the parameter field of the particular instance of the defining word is pushed onto the stack before the runtime words are executed. "does" 
References 
, and C, , Section 2.9.2 

;CODE , Section 4.2 

ALLOT , Section 2.9.1 

CONSTANT , Section 2.7.3 

CREATE , Section 2.7.1 

Defining words, Starting Forth 

DOES> , Section 2.7.6.2 

VARIABLE , Section 2.7.2 
Back to Forth Programming Handbook Index
Back to COMSOL's Forth products page
