Anyone willing to help a beginner?
Author Message
Anyone willing to help a beginner?

Quote:

> I either need a version with [M*/]
> or a working definition of the word
> or even a tip on how to write such a
> definition.

Win32Forth (for 32-bit Windows OSs) has that word, but since it is a
32-bit Forth, it takes a 64-bit double word, multiplies it by a single
32-bit word, and then divides it by another 32-bit word, leaving a
64-bit result.  The easily available 16-bit F-PC and eForth systems do
not seem to have this word.  Maybe someone else knows of another Forth
with it or a nice definition.
--

Tue, 19 Jan 1999 03:00:00 GMT
Anyone willing to help a beginner?

Quote:

> I'm trying to learn Forth83 with Leo Brodie's "Starting Forth".
> I've been doing all the problems, and have made my way half-way through
> the book.  Now, upon reaching the chapter on double-length numbers, I've
> discovered that the version of Forth83 that I have is missing the word
> Forth, all missing that word.  It is supposed to multiply a 32-bit
> number by a 16-bit number and divide the triple-length result by a
> 16-bit number, returning a 32-bit result.  I'm now going to try to write
> my own definition for it, but I'm afraid that I don't have a great
> enough understanding of the material to be successful.  I was going to
> find another version of Forth including the word, and steal the
> definition from that version's source code.  Now, I'd really appreciate
> it if someone could help me out.  I either need a version with the word
> or a working definition of the word or even a tip on how to write such a
> definition.

> Thanks
> Geniece McCollum

Here is an extract of the code extracted from Win32Forth, to do what
you want.

The only problem you will probably still have, is possibly with
having a definition of UM*, UM/MOD and INVERT.  UM* is typically a code word
that returns an unsigned double given two unsigned singles.  That may
be defined already.  INVERT I believe is just -1 XOR, so this might be
enough to get you going.  UM/MOD is probably already defined, but perhaps
with a different name.  It takes a unsigned double, devides by an unsigned
single, and returns unsigned single result and remainder.

I hope this helps,

Tom Zimmer

\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\ MSTARSL.F     ANSI extended precision math by Robert Smith
\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

: TNEGATE   ( t1lo t1mid t1hi -- t2lo t2mid t2hi )
invert >r
invert >r
invert 0 -1. d+ s>d r> 0 d+
r> + ;

: UT*   ( ulo uhi u -- utlo utmid uthi )
swap >r dup>r
um* 0 r> r> um* d+ ;

: MT*   ( lo hi n -- tlo tmid thi )
dup 0<
IF      abs over 0<
IF      >r dabs r> ut*
ELSE    ut* tnegate
THEN
ELSE    over 0<
IF      >r dabs r> ut* tnegate
ELSE    ut*
THEN
THEN ;

: UT/   ( utlo utmid uthi n -- d1 )
dup>r um/mod -rot r> um/mod
nip swap ;

: M*/  ( d1 n1 +n2 -- d2 )
>r mt* dup 0<
IF      tnegate r> ut/ dnegate
ELSE    r> ut/
THEN ;

: M+    ( d1 n -- d2 )
s>d d+ ;

Tue, 19 Jan 1999 03:00:00 GMT
Anyone willing to help a beginner?

I'm trying to learn Forth83 with Leo Brodie's "Starting Forth".
I've been doing all the problems, and have made my way half-way through
the book.  Now, upon reaching the chapter on double-length numbers, I've
discovered that the version of Forth83 that I have is missing the word
Forth, all missing that word.  It is supposed to multiply a 32-bit
number by a 16-bit number and divide the triple-length result by a
16-bit number, returning a 32-bit result.  I'm now going to try to write
my own definition for it, but I'm afraid that I don't have a great
enough understanding of the material to be successful.  I was going to
find another version of Forth including the word, and steal the
definition from that version's source code.  Now, I'd really appreciate
it if someone could help me out.  I either need a version with the word
or a working definition of the word or even a tip on how to write such a
definition.

Thanks
Geniece McCollum

Tue, 19 Jan 1999 03:00:00 GMT
Anyone willing to help a beginner?

writes:

Quote:
>Now, upon reaching the chapter on double-length numbers, I've
>discovered that the version of Forth83 that I have is missing the word
>M*/.
>It is supposed to multiply a 32-bit
>number by a 16-bit number and divide the triple-length result by a
>16-bit number, returning a 32-bit result.
>I'm now going to try to write
>my own definition for it, but I'm afraid that I don't have a great
>enough understanding of the material to be successful.
>I either need a version with the word
>or a working definition of the word or even a tip on how to write such a
>definition.

OK, here are some tips.

I'll start by assuming you have something that does UM* because that
would be a lot of trouble to write high-level from scratch.  Similarly
I'll assume you have UM/MOD for similar reasons.

First multiply a double number by a single.  That isn't hard in
principle.

59
x  7
-----
63
35
-----
413

Do UM* with the bottom half, do UM* with the top half, and add.

Only there's a problem with the carry.  Forth just throws away the
carry bit.  Various people have come up with solutions (Jibari Zakiya,
AKA Doug Ross, made a very good one), but none of them have caught on
because when you really care, you usually care enough to do it in
assembly.  OK, we can write a word that will look at two numbers, add
them together, and leave a 0 or 1 for the carry.

: ADDC ( u1 u2 -- u1+u2 0|1 )

Well, you said you'd settle for tips, so I won't put in the code now.
You can do it by looking at the high bits, using AND OR and XOR.
There's an easier way than fooling with nested IF statements, but if
that's the way you think best the first time around, it's OK.  Just do
something that lets you tell whether you get it or not, and then do it
right the 2nd time.  Or since you're only doing it once, you could add
them as doubles.  The carry works between the halves of double numbers,
it just doesn't work at the top.

OK, next you want to divide a single into a triple.  That isn't too
hard, you can divide the single into the top 2 cells to get a quotient
and remainder.  Then divide it into the remainder with the third cell.
The two quotients will be your double quotient, and the final remainder

69
________
7 )486
42
--
66
63
--
3

That one is easier because the carry doesn't get in the way.

This is enough to do UM*/ .  To do it for signed numbers, you could note
whether exactly one of your numbers is negative, take both absolute
values, do UM*/, and then negate the quotient if needed.  This will give
you a "symmetric" operation instead of a "floored" one.  Negative
numbers come out just like positive ones except for the sign.  For a lot
of purposes floored operations are better, but it takes more thought to
get it right.  If you don't really care about dividing negative numbers,
you could get by with just UM*/ and not think about the rest.

Good luck!

Wed, 20 Jan 1999 03:00:00 GMT
Anyone willing to help a beginner?

: T*  ( u . u -- u . . ) TUCK UM* 2SWAP UM* SWAP >R 0 D+ R> ROT ROT ;
: T/  ( u . . u -- u . ) DUP >R UM/MOD ROT ROT R> UM/MOD NIP SWAP ;
: M*/ ( u . u u -- u . ) >R T*  R> T/ ;

Wed, 20 Jan 1999 03:00:00 GMT
Anyone willing to help a beginner?

Quote:

>> I'm trying to learn Forth83 with Leo Brodie's "Starting Forth".
>> I've been doing all the problems, and have made my way half-way through
>> the book.  Now, upon reaching the chapter on double-length numbers, I've
>> discovered that the version of Forth83 that I have is missing the word
>> Forth, all missing that word.  It is supposed to multiply a 32-bit
>> number by a 16-bit number and divide the triple-length result by a
>> 16-bit number, returning a 32-bit result.  I'm now going to try to write
>> my own definition for it, but I'm afraid that I don't have a great
>> enough understanding of the material to be successful.  I was going to
>> find another version of Forth including the word, and steal the
>> definition from that version's source code.  Now, I'd really appreciate
>> it if someone could help me out.  I either need a version with the word
>> or a working definition of the word or even a tip on how to write such a
>> definition.

>> Thanks
>> Geniece McCollum

>Here is an extract of the code extracted from Win32Forth, to do what
>you want.

>The only problem you will probably still have, is possibly with
>having a definition of UM*, UM/MOD and INVERT.

Here are high-level definitions for UM* and UM/MOD.  These are taken from
MAF (Minimal ANS Forth), which is written for study not for speed, so words
which are code definitions in most Forths are colon definitions in MAF.
([FW] indicates words taken from the FIG UK magazine Forthwrite.)

\ System Characteristics ------------
tI : FindBits/Cell                      \ Computes 2 characteristics of the
( -- Bits/Cell HighBit )           \ implementation.
tI   1 1 BEGIN                          \ Find the HighBit by shifting the
tI     DUP 2*                           \ least significant bit upwards until
tI   WHILE                              \ just before it pops off the top of
tI     2*                               \ the word and leaves 0.
tI     SWAP 1+ SWAP
tI   REPEAT ;

tI FindBits/Cell                        \ Compute the results and record them.
tI   CONSTANT HighBit

tI : SignsDiffer?                       \ Support for <+Loop> < U< and M*.
\    ( n1 n2 -- Truth )                 \ HighBit is set for -ve integers.
tI   XOR                                \ Find the bits which differ.
tI   HighBit AND 0<>                    \ Is one of them the HighBit?
tI ;

tI : US>D                               \ Convert the number u to the
\    ( u -- ud )                        \ number d with the same numerical
tI   0                                  \ value.
tI ;

tI : UD>S                               \ Convert the double number ud to the
\    ( ud -- u )                        \ single number u with the same
tI   DROP                               \ numerical value.
tI ;                                    \ To report 'result out of range',
\ substitute 0<> IF -11 THROW THEN
\ for DROP.

tI : D+                                 \ [FW] From the Double-Number word set.
\    ( d1|ud1 d2|ud2 -- d3|ud3 )        \ Used by UM* and UM/MOD.
tI   >R
tI   ROT OVER +                         \ Add the less significant cells.
tI   DUP >R
tI   U> IF                              \ If their sum is less than one of
tI     1+                               \ them then the addition overflowed,
tI   THEN                               \ so increment one of the more
tI   R>                                 \ significant cells.
tI   SWAP R> +                          \ Add the more significant cells.
tI ;

tI : DU<                                \ [FW] From the Double Number Extension
\    ( ud1 ud2 -- Truth )               \ word set.  Used by UM/MOD.
tI   ROT 2DUP <> IF                     \ If the more significant cells <> ...
tI     SWAP                             \ Exchange them ready for U<.
tI     2SWAP                            \ Prepare to drop the less sig. cells.
tI   THEN
tI   2DROP                              \ Drop the unwanted cells
tI   U<                                 \ and compare the others.
tI ;

\ Multiply and Divide ----------------
\ Design Note: UM* achieves multiplication by repeated doubling and occasional
\ addition.  u1 is doubled in a loop and at each doubling, if the matching
\ bit from u2 is set, then the current value of u1 is added into the result.
\ For example, to multiply 3 by 2 use:
\       5 6 UM*
\ The stack values at points X and Y in the loop will be:
\    X: udProduct   du1  b    Y: udProduct  du1
\             0 0   6 0  1             6 0  12 0
\             6 0  12 0  0             6 0  24 0
\             6 0  24 0  4            30 0  48 0

tI : UM*                                \ Unsigned multiply achieved by
\    ( u1 u2 -- udProduct )             \ repeated doubling and occasional
tI   >R                                 \ Save u2.
tI   1 >R                               \ Save a bit mask, m, initially 1.
tI   0 US>D                             \ udProduct, initially 0.
tI   ROT US>D                           \ Convert u1 to du1 to give
tI                                      \ -- udProduct du1 ).
tI   BEGIN                              \ For every bit in u2 ...

tI     SWAP 2* >R                       \ Double m and save it.
tI                            \ X       \ -- udProduct du1 b ) ( R:-- u2 m*2 )
tI     IF                               \ If b is set ...
tI       2SWAP 2OVER D+ 2SWAP           \ Add du1 to udProduct.
tI     THEN
tI     2DUP D+                \ Y       \ Double du1.

tI   OR UNTIL
tI   2DROP R> R> 2DROP
tI ;

tI : M*                                 \ Signed multiply.
\    ( n1 n2 -- d )
tI   2DUP SignsDiffer? >R               \ Save the flag.
tI   ABS SWAP ABS                       \ Convert to unsigned
tI   UM*                                \ and multiply.
tI   R> IF                              \ Apply sign if needed.
tI     DNEGATE
tI   THEN
tI ;

\ Design Note: (UM/Mod) achieves division by repeated doubling and occasional
\ addition.  Recursion is used to provide two matching loops used as follows.
\ The divisor ud2 is saved on the return stack and doubled in the first loop.
\ The remainder ud3 is given the initial value ud1 and the quotient u4 is
\ initially 0.
\ A second loop is now executed the same number of times as the first,
\ doubling u4 with each cycle and comparing ud3 with the appropriate ud2i
\ taken from the return stack.
\ For example, to divide 7 by 2 use:
\       7 0  2 0  (UM/Mod)
\ The stack values at points X and Y in the second loop will be:
\    X: u4 ud3  ud2                         Y: ud3  u4
\       0  7 0  8 0  TRUE  => no action =>     7 0  0
\       0  7 0  4 0  FALSE =>  action   =>     3 0  1
\       2  3 0  2 0  FALSE =>  action   =>     1 0  3

tI : (UM/Mod)                           \ Support for UM/MOD, factored out
\    ( ud1 ud2 -- ud3 u4 )              \ to allow recursion.  Gives quotient
\ u4 and remainder ud3.
tI   2DUP >R >R                         \ Save value of ud2i in this cycle.
tI   2OVER 2OVER DU<                    \ If ud2i is now > ud1 or
tI   OVER HighBit AND                   \ ud2i cannot double again ...
tI   OR IF                              \ cease recursion.
tI     2DROP 0                          \ Set ud3=ud1, u4=0 and let recursion
tI   ELSE                               \ unwind.
tI     2DUP D+                          \ Double ud2i
tI     RECURSE                          \ and repeat
tI     2*                               \ As recursion unwinds,
tI   THEN                               \ double u4 (initially u4=0).
tI   ROT ROT                            \ Bury u4 under ud3.
tI   R> R>                              \ Fetch ud2i for this cycle.
tI   2OVER 2OVER DU<      \ X
tI   IF                                 \ If ud3 < ud2i ...
tI     2DROP ROT                        \ Tidy up.
tI   ELSE                               \ Else do the work ...
tI     DNEGATE D+                       \ ud3 = ud3 - ud2i
tI     ROT 1+                           \ Increment u4.
tI   THEN                 \ Y
tI ;

tI : UM/MOD   \ ( ud1 u2 -- u3 u4 )     \ Divide ud1 by u2, giving the
tI   ?DUP IF                            \ quotient u4 and the remainder u3.
tI     US>D (UM/Mod) >R UD>S R>
tI   ELSE                               \ If ud1=0 ...
tI     2DROP 0 0                        \ this code just returns 0 0.
\                                       \ To report 'divide by 0', substitute
tI   THEN                               \ -10 THROW.
tI ;

tI : FM/MOD                             \ [FW] divide d1 by n1 giving the
\    ( d1 n1 -- n2 n3 )                 \ floored quotient n3 and the
\ remainder n2.
tI   DUP >R ABS                         \ Save n1 and make it +ve.
tI   ROT ROT DUP >R DABS                \ Save d1 and make it +ve.
tI   ROT UM/MOD                         \ -- n2 n3 )

tI     OVER IF                          \ if the remainder n2 <> 0 ...
tI       1+                             \ increment the quotient n3.

tI     THEN
tI     NEGATE                           \ n3 = -n3
tI   THEN
tI   R> 0< IF                           \ If n1 -ve ...
tI     SWAP NEGATE SWAP
...

Wed, 20 Jan 1999 03:00:00 GMT
Anyone willing to help a beginner?

Quote:

> Here is an extract of the code extracted from Win32Forth, to do what
> you want.

My version of M*/ isn't factored so good, but it does it's work, and has
much less IFs:

: m*/ ( d1 n2 u3 -- dqout ) \ double m-star-slash
>r s>d >r abs -rot
s>d r> xor r> swap >r >r dabs rot tuck um* 2swap um*

r> IF dnegate THEN ;

This is however a typical example of write-only Forth, so I better
should be ashamed of it and not post it ;-).

--
Bernd Paysan
http://www.informatik.tu-muenchen.de/~paysan/

Thu, 21 Jan 1999 03:00:00 GMT
Anyone willing to help a beginner?

Quote:

> My version of M*/ isn't factored so good, but it does it's work, and has
> much less IFs:

> : m*/ ( d1 n2 u3 -- dqout ) \ double m-star-slash
>     >r s>d >r abs -rot
>     s>d r> xor r> swap >r >r dabs rot tuck um* 2swap um*

>     r> IF dnegate THEN ;

> This is however a typical example of write-only Forth, so I better
> should be ashamed of it and not post it ;-).

You obviously haven't seen much of that standard C++ library code! The
low-level parts of any language is probably hard to read.

The point is that once this word has been fully tested, you can just use
it without wondering how it is implemented. Is this necessarily harder to
read that Forth primatives written in some strange assembler?

--

Finnigan Corporation
2215 Grand Avenue Parkway        Tel: (512) 251-1574
Austin, TX  78728-3812           Fax: (512) 251-1547

Mon, 25 Jan 1999 03:00:00 GMT
Anyone willing to help a beginner?

Quote:

> > My version of M*/ isn't factored so good, but it does it's work, and has
> > much less IFs:

> > : m*/ ( d1 n2 u3 -- dqout ) \ double m-star-slash
> >     >r s>d >r abs -rot
> >     s>d r> xor r> swap >r >r dabs rot tuck um* 2swap um*

> >     r> IF dnegate THEN ;

> > This is however a typical example of write-only Forth, so I better
> > should be ashamed of it and not post it ;-).

> You obviously haven't seen much of that standard C++ library code! The
> low-level parts of any language is probably hard to read.

After having a closer look to it (I just wrote it once and forgot about
details), it is indeed both "factored" and more maintainable I thought the
first time. The only problem is that the factors (get absolute values,
multiply and divide) are spread over all the first three lines.

Quote:
> The point is that once this word has been fully tested, you can just use
> it without wondering how it is implemented.

Point well taken!

Quote:
> Is this necessarily harder to
> read that Forth primatives written in some strange assembler?

No, and since you can try to understand what is done by decomposing and
executing it step by step, you have a good chance to find out how it's
working. Do this with a strange assembler somewhere deep in libc ;-).
--
Bernd Paysan