Jump to content
IGNORED

Forth Primer: Factoring code for clarity #6


TheBF

Recommended Posts

While looking at how to implement sprites I studied the old TI-Forth code that Lee has published for some clues.

 

I found this piece of code that seemed hard to understand.

: DXY ( X2 Y2 X1 Y1 --- X^2 Y^2 )
     ROT - ABS ROT ROT - ABS DUP * SWAP DUP *

I am sure the author was very proud of this tight statement with all stack juggling working out just perfect.

But I find it hard to understand the intentions of the code.

 

So I took it apart by removing the code that repeats and giving it a name.

This is how Forth code is commonly "re-factored".

 

So the first this I see is DUP *. Take a number on the stack and make a copy then multiply them together.

That is like saying X^2 in BASIC.

 

So I made this word:

: ^2  ( n -- n')  DUP * ;

Now at the Forth console I can type 2 ^2 . and it prints 4. Perfect.

 

Also noticed the phrase " - ABS" is used twice... so if you subtract 2 numbers and take the absolute value you have a calculation for the Delta, between them.

 

So how about this definition:

: DELTA ( n n -- n') - ABS ;

I also noticed the "ROT ROT". Rot takes 3 numbers on the stack and "rotates" the 3RD number to the TOP position.

 

So 1 2 3 ROT will give you 2 3 1 on stack.

 

Doing 1 2 3 ROT ROT will give you 3 1 2, so it is like a backwards rotate,

There is a Forth word to do that called "-ROT" so I replaced those 2 words with 1 word.

 

So with those factors removed the DXY word became.

: DXY     ( x2 y2 x1 y1 -- x^2 y^2 )
          ROT DELTA -ROT DELTA ^2  SWAP ^2 ;

It still has some stack juggling noise in it, but by choosing meaningful names I can see that it takes 2 sets of x/y coordinates, gets the delta between the x and y parts and computes the square of each delta.

 

IMHO, that is how you make Forth easier to read for the next poor guy who has to read your code.

Create small, well named definitions. Soon the code starts to read clearly.

 

B

Edited by TheBF
  • Like 1
Link to comment
Share on other sites

Yes that's evil!

 

I like the way you factored it.

 

I think this would do the same, no?

 

>r swap >r - abs dup * ( x^2 )
r> r> - abs dup *      ( x^2 y^2 )
Again, not as neat as yours but easier than the first version. I always forget which way ROT rotates! Edited by Willsy
Link to comment
Share on other sites

Because DXY reports the squares of Δx and Δy, the two instances of ABS are superfluous. When I developed fbForth 2.0, I converted most of the graphics primitives from high-level Forth to Assembler code before hoisting them into cartridge space. I optimized words where I saw the need. DXY was one such word. Now, optimizing your DELTA in this manner would render it, perhaps, an unnecessarily expensive synonym for - .

 

...lee

Link to comment
Share on other sites

For the high level Forth, a combination of ROT and return stack use (below, “S:” represents the parameter stack and “R:”, the return stack):

 

: DXY ( x2 y2 x1 y1 --- x^2 y^2 )
ROT - DUP * >R \ S:X2 X1 R:dy^2
- DUP * \ S:dx^2 R:dy^2
R> \ S:dx^2 dy^2
;

 

...lee

Link to comment
Share on other sites

LOL. Very cool Lee. Of course the ABS is redundant. The master speaks again.

 

So I thought since I was still up I would measure these beasts.

I did a version of mine with DELTA removed as well.

 

In my current kernel -ROT is : -ROT ROT ROT ; so no speed advantage there.

 

But... there was no real penalty for factoring out ^2 on my system.

 

Yes there was a penalty but it was masked by the very slow ROT and -ROT words written in Forth.

This black screen version has code words.

 

Here is the code. (apologies for the timer name. I ran out of space in 8K so I squeaked it in) :-)

 

​I fixed the copy and paste errors in the original version. This one seems correct now.

\ factoring dxy tests
HEX
\ TMR! sets the 9901 timer to >3FFF
\ TMR@ reads the 9901 timer
: TIDXY ( X2 Y2 X1 Y1 --- X^2 Y^2 )
     ROT - ABS ROT ROT - ABS DUP * SWAP DUP * ;
: ^2      ( n -- n^2)  DUP * ;
: DELTA   ( n -- n')   - ABS ;
: BFDXY     ( x2 y2 x1 y1 -- x^2 y^2 )
          ROT DELTA -ROT DELTA ^2  SWAP ^2 ;
: BFDXY2     ( x2 y2 x1 y1 -- x^2 y^2 )
          ROT - -ROT - ^2  SWAP ^2 ;

: WILLXY
        >R SWAP >R - ABS DUP * ( x^2 )
        R> R> - ABS DUP * ;    ( x^2 y^2 )
: LEEXY  ( x2 y2 x1 y1 --- x^2 y^2 )
    ROT - DUP * >R    \ S:X2 X1  R:dy^2
    - DUP *           \ S:dx^2   R:dy^2 
    R>                \ S:dx^2 dy^2 
;
: INPUTS   10 20 30 40 ;
: .OUTPUT  ( n n t -- ) >R . .  3FFF R> - . ;
: TESTTI     INPUTS  TMR!  TIDXY TMR@ .OUTPUT  ;
: TESTBF     INPUTS  TMR!  BFDXY TMR@ .OUTPUT  ;
: TESTBF2    INPUTS  TMR!  BFDXY2 TMR@ .OUTPUT ;
: TESTWILL   INPUTS  TMR!  WILLXY TMR@ .OUTPUT  ;
: TESTLEE    INPUTS  TMR!  LEEXY TMR@  .OUTPUT  ;

 


post-50750-0-97663900-1495517192.jpg

Edited by TheBF
Link to comment
Share on other sites

I really need to get a life :-)

 

But I had to see what coding the word would do and the results are amazing.

CODE: DXY ( x2 y2 x1 y1 --- x^2 y^2 )
          *SP+ R0 MOV,      \ x1->R0
          *SP+ TOS SUB,     \ y1-y2->tos
          *SP  R0 SUB,    \ x1-x2->R0
           TOS R3 MOV,      \ dup tos
           TOS R3 MPY,     \ tos^2, result->R4 (tos)  ( edit: removed and instruction here)

           R0  R2  MOV,     \ dup R0
           R2  R0  MPY,     \ RO^2
           R1 *SP  MOV,     \ result to stack
           NEXT,            \ 16 bytes
           END-CODE

The code word is the 2 bytes smaller (after editing) than Lee's Forth version I believe, 18 bytes vs 16

But it is 3.375 times faster than Lee's version and 5.5 Times faster that my factored version.

 

Just adding ROT to word slows it down a lot it seems.

Makes me wish for register based locals for things like this.

post-50750-0-60962300-1495546813.jpg

Edited by TheBF
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...