Miscellaneous
Solution 2.7 Define words OCTAL and BINARY which will set the system to base 8 and base 2 respectively.
: OCTAL ( -- ) 8 BASE ! ; : BINARY ( -- ) 2 BASE ! ; : .BASE \ --
BASE @ DUP DECIMAL . BASE ! ;
: .BIN \ n --
BASE @ SWAP \ -- base n
BINARY U. BASE ! ;
Solution 2.8: The word +! is present in all Forth all systems, but can you define your own version using the Forth words described so far? Call your version MY+! and test it.
: MY+! \ n addr -- SWAP OVER @ + SWAP ! ;
: MY+! \ n addr -- DUP @ ROT + SWAP ! ;
Solution 2.9: Define variables TEMP and PRESSURE and a word CHECK with the following specification.
Solutions to Exercises
Flag is true if the value stored in TEMP is less than 700 and the value stored in
PRESSURE is between 1200 and 2200 inclusive. Make sure that your definition of
CHECK produces the following results.
600 TEMP ! 1200 PRESSURE ! CHECK . ( -1 ok ) 2200 PRESSURE ! CHECK . ( -1 ok }
2201 PRESSURE ! CHECK . ( 0 ok )
2200 PRESSURE ! 700 TEMP ! CHECK . ( 0 ok ) 1199 PRESSURE ! -1 TEMP +! CHECK . ( 0 ok )
Solutions:
VARIABLE TEMP \ -- addr
VARIABLE PRESSURE \ -- addr
: CHECK \ -- flag
TEMP @ 700 < \ -- flag1
PRESSURE @ 1200 1201 WITHIN \ -- flag1 flag2 AND
;
Alternative solution:
: CHECK \ -- flag
TEMP @ 700 <
PRESSURE @ 1199 > \ -- flag1 flag2
PRESSURE @ 2201 < \ -- flag1 flag2 flag3 AND AND
;
Solution 2.10: Define the word TEST with the following specification.
n -- flag
: TEST \ n –- flag
\ Leaves a true flag if n < 50 or n >100, and leaves \ a false flag otherwise.
DUP 50 < \ -- n flag1
SWAP 100 > \ -- flag1 flag2 OR
;
: TEST \ n -- flag
50 101 WITHIN 0= ;
Solution 2.11: Define the words >= and <= with the following specs.
>= \ n1 n2 -- flag
Flag is true if n1 is greater than or equal to n2
<= \ n1 n2 -- flag
Solutions to Exercises
: >= ( n1 n2 -- flag ) < 0= ; : <= ( n1 n2 -- flag ) > 0= ;
Solution 2.12: Code and trace the execution of 20 10 MAX, where MAX is defined as:
: MAX \ n1 n2 -– flag 2dup >
if drop else swap drop then ;
You may have to perform the trace manually, depending on the facilities of your Forth system. For example on an optimised Forth, the following machine code may result.
dis max MAX
( 0049EB70 3B5D00 ) CMP EBX, [EBP] ( 0049EB73 0F8D0B000000 ) JNL/GE 0049EB84 ( 0049EB79 8B5D00 ) MOV EBX, [EBP] ( 0049EB7C 8D6D04 ) LEA EBP, [EBP+04] ( 0049EB7F E903000000 ) JMP 0049EB87 ( 0049EB84 8D6D04 ) LEA EBP, [EBP+04] ( 0049EB87 C3 ) NEXT, ( 24 bytes, 7 instructions ) ok 2DUP -- 20 10 20 10 > -- 20 10 -1 IF (true) -- 20 10 DROP -- 20 THEN -- 20
Code and test a definition for MIN. This has the specification:
MIN n1 n2 -- n3
Where n3 is the signed minimum of n1 and n2.
: MIN \ n1 n2 -– flag 2dup <
if drop else swap drop then ;
Solution 2.13: Define versions of MAX and MIN with an IF ... THEN construct, i.e., without using an ELSE.
: MAX \ n1 n2 -- flag 2DUP < IF SWAP THEN DROP ; : MIN \ nl n2 -- flag 2DUP > IF SWAP THEN DROP
Solutions to Exercises
Solution 2.14: Define words to meet the following specifications.
TEST1 n1 -- n2 If $n_1 > 100$ then $n_2 = 2 times n1 else n2 = n1 - 20 TEST2 n1 n2 -- n3 If n1 > n2 then n3 = 1000 else n3 = n1 : TEST1 \ n1 -- n2 DUP 100 > IF 2 * ELSE 20 - THEN ; : TEST2 \ n1 n2 -- n3 OVER < IF DROP 1000 THEN ;
Solution 2.15: Suppose the variables TEMP and HEATER-SWITCH have been declared as part of an industrial simulation. TEMP holds a simulated temperature and HEATER- SWITCH holds a value that indicates whether a simulated heater is on or off. Code a word STC (``simulate temperature change'') which has the following spec.
If the value held in HEATER-SWITCH is non zero, add 2 to the value held in TEMP
otherwise subtract 1 from the value held in TEMP.
: STC \ --
HEATER-SWITCH @
IF 2 ELSE -1 THEN TEMP +!
;
Solution 2.16: Define a word .B (``print boolean'') which removes the top stack item and prints ``true'' if its value is non zero and ``false'' if its value is zero. The word can be used like this:
5 6 < .B <cr> true ok
: .B \ flag --
IF ." true" ELSE ." false" THEN ;
Solution 2.17: The definition of ABS can be written without an IF, can you see how?
: ABS \ n1 -- n2 DUP NEGATE MAX
Solutions to Exercises
You can also define ABS without IF and with simpler operations than MAX (which often contains an internal branch):
: abs
dup 0< tuck xor swap – ;
However, that depends on 2s-complement arithmetic and, on many CPUs, 0< requires an internal branch.
Solution 2.18:
Code Euclid’s algorithm in Forth, with the following specification:
GCD x y -- z
z is the greatest common divisor of x and y.
While they are not equal
Arrange pair so smaller is first 16 24 8 16 Put copy of first after second. 16 24 16 8 16 8
Subtract the two rightmost 16 8 8 8
Endwhile
Delete the second number 8
This can be coded in Forth as:
: ORDER \ n1 n2 -- smaller larger 2DUP > IF SWAP THEN ; : GCD \ n1 n2 -- n3 BEGIN 2DUP <> WHILE ORDER OVER - REPEAT DROP ;
Solution 2.19: Code a version of GCD using Euclid's algorithm and a BEGIN ... UNTIL loop.
: ORDER \ n1 n2 -- smaller larger 2DUP > IF SWAP THEN ; : GCD \ n1 n2 -- n3 BEGIN ORDER OVER - DUP 0= UNTIL
Solutions to Exercises
;
Solution 2.20: The combined electrical resistance R offered by two resistors with values R1 and R2 connected in parallel is given by:
R = {{R1 * R2} / {R1 + R2}}
Define a word //RES with the following spec:
//RES R1 R2 -- R
Leaves R, the resistance obtained by connecting R1 and R2 in parallel.
Define a word ///RES which calculates the value of three resistors connected in parallel.
: //RES ( R1 R2 -- R ) 2DUP + */ ; : ///RES ( R1 R2 R3 -- R ) //RES //RES ;