Logic and Comparison

Logic

AND INVERT OR XOR LSHIFT RSHIFT

I'll not give pseudocode for any of these. AND INVERT OR XOR are all bitwise operators, acting on every bit of the cell.

LSHIFT \ x1 u -- x2 ; shift x1 left u places, filling with zero
RSHIFT \ x1 u -- x2 ; shift x1 right u places, filling with zero

Comparison

0< 0= 0<> < > MAX MIN WITHIN NEGATE U<

0< 0= 0<> < > all act as you would expect, returning a flag with all bits set for TRUE, or zero for FALSE.
U< is similiar but for unsigned numbers (see below)

MAX  (n1 n2 -- n3) POP PSP TO W  TOS W < IF  W TO TOS THEN NEXT

MIN   (n1 n2 -- n3) POP PSP TO W  TOS W > IF  W TO TOS THEN NEXT

: WITHIN \ n1 n2 n3 -- f ; true if n2 <= n1 < n3
        OVER - >R - R> U< ;

WITHIN also works for unsigned numbers, so if n2 > n3 then n1 n2 n3 WITHIN is true if n1 > n2

Signed and Unsigned Numbers

The form of signed number representation usually used is called two's complement, and that is the only form I will deal with. Negative numbers are represented by inverting all the bits of the positive equivalent and adding one. The same operation repeated returns the original number. Hence:

: NEGATE INVERT 1+ ;

The largest possible number (all bits set), when seen as a signed number, is -1. It can easily be seen that adding 1 to -1 gives zero. HALFMAX (only high bit set), which we saw when discussing the runtime looping words, is the most negative number, obtained by adding one to the largest postive signed number. This circular arrangement of numbers is seen in the behaviour of words like WITHIN above

Since a TRUE flag is also -1, arithmetic can be done on that too. Forth words do not care where their arguments come from! Conditionals such as IF will regard any number of bits set as a true flag, but to make it 'canonical' use:

0<> ( x -- 0 | -1 ) TOS IF -1 TO TOS THEN NEXT

Thus: : 0< HALFMAX AND 0<> ;

A high-level U< can be written:

: U<   \ ni n2 -- f
2DUP XOR 0< IF      \ signs differ?
DROP 0<      \ if n1 < 0 then n2 > 0
      ELSE < THEN ;