I hope the stack effect of these simple words is obvious. If not, I'll include a stack comment. But multiply and divide leave the addend on the stack. It is often unnecessary and always a nuisance to remove. Call it an abandoned number, which I'll indicate by . (and multiple such by ..) in comments.

The C18 has no subtract instruction, but there are several ways to accomplish subtraction. With a and b on the stack (b on top):

- Classic Forth: subtract b from a

- . + 1 . +

or

negate +

with negate defined below - Subtract a from b

- . + - - Subtract b from a with result one less

- . +

with 1 to be added later. Often a single fix-up constant can be added at the end of an expression. Sometimes it doesn't matter.

These are simple functions, often useful:

- negate - 1 . + ;
- abs -if - 1 . + then ;
- max - over . + - -if drop ; then + ;
- min - over . + - -if + ; then drop ;

The ALU must be in add-with-carry mode, which means the code must be compiled at an address with the 200 bit set. The words +cy and -cy set and reset this bit in the current code address.

Carry must usually be clear to start adding. It will remain clear if the last + doesn't overflow.

Clear carry (carry mode) (This code is usually in a node's ROM, address 2d3.):

- clc dup dup or dup + drop ;

Add an unsigned 18-bit number to a 36-bit number (carry mode, carry clear):

- +u + push 0 + pop ;

Negate a 36-bit number:

- -d - push - pop 1 +u ;

Shift left a 36-bit number:

- In carry mode, carry clear

2*d dup + push dup + pop ; - Without carry

2*d -if push - 2* - pop 2* ;

then push 2* pop 2* ;

Shift right a 36-bit number:

- 2/d 2/ 2* a! +* a ;

Sign-extend an 18-bit number to 36 bits:

- sign dup push dup -if or - pop ; then or pop ;

- +d a! push a . + a! pop . + a ;

- +s sign +d ;

The multiplicand is often left on the stack. The carry bit is not used or changed by the +* instruction.

Unsigned multiplier, signed multiplicand, 36-bit signed product:

- * a! 0 17 for +* unext a ;

If the multiplier is signed, its high-order bit indicates a subtract:

- * a! 0 16 for +* unext - . +* - a ;

Unsigned multiply, necessary for multiple-precision arithmetic. From Michael:

- Two 18-bit unsigned numbers yield 36-bit unsigned product
- If multiplicand is negative, add multiplier to high-order product
- u* uu-hl over a! 0 8 for +* . +* unext

push -if drop pop . + a ;

then drop drop pop a ; - From Greg: putting 2 +*s inside unext saves 9 ns

Multiply and add x:

- *+ nxn-n a! 17 for +* next drop drop a ;

A faster 18-bit product can be computed from 2 numbers whose bits add up to 18; say 9 and 9. the multiplier (top of stack) is a normal right-justified unsigned integer. The signed multiplicand is expected to be left-shifted the number of bits in the multiplier. The product will be an 18-bit signed integer.

- * a! 0 8 for +* unext ;

Divide is slower than multiply, since there is no divide step instruction. In carry mode with carry undefined:

- /mod hld-rq a! 17 for begin dup + push dup +

dup a . + -if drop pop *next dup + ;

then over or or pop next dup + ;

If the dividend is signed:

- -/mod push over -if drop -d pop /mod - 1 . + ; then drop pop /mod ;

For a single-precision divide with a small quotient, this is shorter and faster, without carry:

- /mod nd-rq a! 3ffff for dup a . + -if drop pop - ; then next

The quotient is on top, so:

- / /mod push drop pop ;

mod /mod drop ;

*/ is a classic Forth word. It multiplies a number by a ratio. With 3 numbers on the stack, the top is the divisor. The 36-bit intermediate product preserves precision:

- */ push * pop / ;

- sqrt 2*d 2*d push push 0 pop 10000

loop if a! over 2* over - . + a . +

-if - push drop a or pop dup

then drop pop 2*d push a 2/ loop ;

then drop drop pop drop ;

For fractional arithmetic it's useful to define 1. In this context:

- 1. 1ffff ;

- .f 1. 10000 */ ;

.0 10000 1. */ ;

If the multiplier is positive:

- *. a! 0 17 for *+ unext a -if drop - 2* - ; then drop 2* ;

*. * -if drop - 2* - ; then drop 2* ;

If the multiplier is signed, its high-order bit indicates a subtract:

- *. a! 0 16 for *+ unext - . *+ - a -if drop - 2* ; then drop 2* - ;

- 1. 32678 ;

16-bit code requires an additional left shift to the 17-bit code:

- *. *.17 a 2* -if drop - 2* - ; then drop 2* ;

- /. push 0 pop / ;

- 0n a a! 0 n for dup !+ unext drop ;

With b a on the stack, b is added into a. Both addresses are discarded. n is the number-1 of 18-bit words in such numbers. In carry mode:

- +n ba n for push a! @+ push a pop pop a! @ . + !+ a next drop drop ;

- +cy +c + ; -cy

+n ba a! n for dup b! @b @ +c !+ 1 + next drop ;