Jump to content
IGNORED

FORTH and BASIC graphic program comparison


TheBF

Recommended Posts

I have been amazed at the level of BASIC programs people are generating here for TI-99.

I spent many hours a few decades ago (ya that sounds weird to me too) inside XB myself.

 

To continue my torture I decided to add TI-BASIC style GRAPHIC words to CAMEL99.

 

Out of curiosity I wrote a program with the new additions and then duplicated it in TI-BASIC.

 

I was amazed at how with these higher level functions the two programs lined up.

 

However I did have make a quick and dirty random number generator. :_(

Raw Forth like Assembler is pretty low level. But that's the game with it. Raise the level.

 

I have some 10 second videos but they need converting and it's late.

I will do it another day. (*EDIT* VIDEO IS ATTACHED)

 

By the way, the color set numbers are correct because Forth accesses 32 color sets

provided by the VDP chip so char 131 is in it's color set 16.

( Graphics test program  )

VARIABLE RND#
HEX
: SCRAMBLE   ( -- n) 83D6 @ 8379 C@ * C3E9 XOR ; ( we had to build a random number generator)
: RANDOMIZE  ( -- ) SCRAMBLE RND# ! ;            ( named it like TI-BASIC )

: RND  ( n -- )                                  ( this one too )
        RND# @ SCRAMBLE XOR >< ABS
        DUP RND# ! SWAP MOD ;

DECIMAL
: RND(X)   ( -- x) 23 RND 1+ ;       ( no sense in repeating the math)
: RND(Y)   ( -- y) 31 RND 1+ ;       ( when it is so easy to call it )
: RND(C)   ( -- c) 15 RND 1+ ;

HEX" FFFF 0000 FFFF 0000" 131 CHARDEF ( 20 CALL CHAR(159,F0F00F0FF0F00F0F")  )
: STUFF                              ( 25 REM STUFF  name of routine)
BEGIN CLEAR                          ( 30 CALL CLEAR) ( BEGIN is like line# 30, to jump back to)
      RND(C) SCREEN                  ( 40 CALL SCREEN(INT(RND*16)+1) )
      16 RND(C) RND(C) COLOR         ( 50 CALL COLOR(16,INT(RND*16)+1,INT(RND*16)+1) )
      RND(Y) 0 ?DO                   ( 60 FOR I=1 TO INT(RND*32)+1 )
      RND(Y) RND(X) 131 RND(X) VCHAR ( 70 CALL VCHAR(INT(RND*24)+1,INT(RND*32)+1,159,INT(RND*24)+1))
      LOOP                           ( 80 NEXT I )
      20000 0 DO                     ( 90 FOR X=1 TO 200 ) ( yes loops are about 100x faster)
      LOOP                           ( 100 NEXT X )
      KEY? ABORT" *Break"            ( 105 REM FORTH loops don't have BREAK built-in)
AGAIN ;                              ( 110 GOTO 30  )  ( actually GOTO BEGIN )


TI-BASiC CAMEL99 GRAPHICS.mov

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

Very nice!

 

I must say, though, that the TI Basic and CAMEL99 Forth programs are not directly comparable when it comes to the RND function. RND in TI Basic, TI Extended Basic, TurboForth, TI Forth and fbForth does not randomize the random-number seed. It produces a reproducible pseudo-random-number sequence with the same starting seed, which is typical of RND in most (all?) computer languages to allow for adequate debugging. The 16-bit seed for all of the above-enumerated languages is at >83C0, which is set to a truly random value at the instant the user selects an item on the TI-99/4A startup menu screen. TI Basic actually sets >83C0 unconditionally to >3767 when it starts. XB continues to increment >83C0 (each VDP interrupt?) until a Basic program is started and resumes incrementing until another program start. The Forths let it be.

 

Regarding the speed comparison of your two programs, I dare say the biggest slow-down for the TI Basic program is RND() because RND() is working on a floating point number, which is 8 bytes long! TI Basic’s RND() calls the GPL RAND function for each of the bytes at least once—so, a minimum of 8 times. Before RANDing the 7 mantissa digits, RND() calls RAND up to 63 times, decrementing the exponent byte (starts at >3B) each time, until RAND returns a non-zero value or the exponent byte = 0. In the extremely unlikely event that RAND never returned non-zero while RND() was working on the exponent, RND() would make 70 calls to RAND, changing >83C0 each time! To summarize, TI Basic’s RND() makes 8 – 70 calls to the GPL RAND function every time it runs, rarely coming anywhere near the 70-call end, however.

 

...lee

Link to comment
Share on other sites

Very nice!

 

I must say, though, that the TI Basic and CAMEL99 Forth programs are not directly comparable when it comes to the RND function. RND in TI Basic, TI Extended Basic, TurboForth, TI Forth and fbForth does not randomize the random-number seed. It produces a reproducible pseudo-random-number sequence with the same starting seed, which is typical of RND in most (all?) computer languages to allow for adequate debugging. The 16-bit seed for all of the above-enumerated languages is at >83C0, which is set to a truly random value at the instant the user selects an item on the TI-99/4A startup menu screen. TI Basic actually sets >83C0 unconditionally to >3767 when it starts. XB continues to increment >83C0 (each VDP interrupt?) until a Basic program is started and resumes incrementing until another program start. The Forths let it be.

 

Regarding the speed comparison of your two programs, I dare say the biggest slow-down for the TI Basic program is RND() because RND() is working on a floating point number, which is 8 bytes long! TI Basic’s RND() calls the GPL RAND function for each of the bytes at least once—so, a minimum of 8 times. Before RANDing the 7 mantissa digits, RND() calls RAND up to 63 times, decrementing the exponent byte (starts at >3B) each time, until RAND returns a non-zero value or the exponent byte = 0. In the extremely unlikely event that RAND never returned non-zero while RND() was working on the exponent, RND() would make 70 calls to RAND, changing >83C0 each time! To summarize, TI Basic’s RND() makes 8 – 70 calls to the GPL RAND function every time it runs, rarely coming anywhere near the 70-call end, however.

 

...lee

 

Wow that is a lot of overhead for a random number. I will look into how you do it in a "system compatible" way.

​Thanks for the continued schooling Lee

 

BF

Link to comment
Share on other sites

 

Wow that is a lot of overhead for a random number. I will look into how you do it in a "system compatible" way.

​Thanks for the continued schooling Lee

 

BF

 

:)

 

Yeah—and as Rich (@RXB) has noted many times before, TI Extended Basic’s RND() does its own thing and takes even longer (much longer) than TI Basic’s RND(). One of these days, perhaps, I will attempt to see how XB does it. And, even though I made a point of the possible maximum 70 times RAND can be called by TIB’s RND(), I would be willing to bet it rarely gets called more than 10 times, which would mean the first 2 calls to RAND both return 0.

 

Re “continued schooling”, I suspect that can get a little irritating, but I usually cannot help myself, particularly when someone makes the mistake :grin: of appearing to listen.

 

...lee

Link to comment
Share on other sites

Yea I can save you the hassle of looking it is due to using Floating Point ALL THE TIME for all calculations unlike TI Basic RND that only return the Floating Point result.

[0898]               * Initialize random number generator 
[0899] A28D 31,00,0A INTRND MOVE 10,G@X2SEED,V@RNDX2
       A290 A3,A0,A2
       A293 95
[0900] A294 00              RTN
[0901] A295 42,03,23 X2SEED BYTE >42,>03,>23,>15,>00 * =   33521, X2 INITIAL VAL
       A298 15,00
[0902] A29A 43,02,3E X1SEED BYTE >43,>02,>3E,>2A,>17 * = 2624223, X1 INITIAL VAL
       A29D 2A,17
[0903]               ***********************************************************
[0904]               *                                                         *
[0905]               * RXB PATCH REPLACEMENT CODE FOR RND WITH TI BASIC RND    *
[0906]               *                                                         *
[0907]               ***********************************************************
[0908]               *           PSEUDO-RANDOM NUMBER GENERATOR
[0909]               *      X(N+1) = (A*X(N)+C) MOD M;  RND = X/M
[0910]               *    WHERE:                 X = X2 * 1E7 + X1
[0911]               *                           A = A2 * 1E7 + A1
[0912]               *                           C = C2 * 1E7 + C1
[0913]               *                           M = 1E14
[0914]               * ASSUMPTIONS:
[0915]               *  (1) All numbers are integers; fractional parts are
[0916]               *      truncated
[0917]               *  (2) If the variables listed below start in the ranges

99/4 GPL-ASSEMBLER (Pass 3) correct                                   PAGE 0016 
EQUATES EXEC-359
[0918]               *     specified. They will also end in the ranges specified
[0919]               *
[0920]               * CONSTANTS: 0 <= A2 < 5E6 ; 0 <= C2 < 1E7
[0921]               *            0 <= A1 < 5E6 ; 0 <= C1 < 1E7
[0922]               * VARIABLES: 0 <= X2 < 1E7 ; 0 <= T1 <= 1E14 ; 0 <= T2 < 1E
[0923]               *            0 <= X1 < 1E7 ; 0 <= T3 <= 1E14 ; 0 <= T4 < 1E
[0924]               *
[0925]               *        STACK USAGE:
[0926]               *            CONSTANT REFS      CONTANT REFS    CONTANT REF
[0927]               * +---------+      IN/OUT            IN/OUT          IN/OUT
[0928]               * | STACK+4 | X2*A1(F)(H)       --    ----      --    ----
[0929]               * +---------+
[0930]               * | STACK+3 |   T2 (C)(J)       --    ----      --    ----
[0931]               * +---------+
[0932]               * | STACK+2 |   T1 (B)(D)   new X1   (E)(N)     --    ----
[0933]               * +---------+
[0934]               * | STACK+1 |old X1(A)(G)       T3   (K)(L) new X2   (M)(P)
[0935]               * +---------+
[0936]               ***********************************************************
[0937]               * COMPUTE NEW VALUE FOR X1, SAVE IT IN V@RNDX1
[0938]               *                             STACK
[0939]               *                               SREFS   FAC CONTENTS
[0940]               * NRND   MOVE 5,V@RNDX1,@FAC        FAC = X1
[0941]               *        MOVE 5,V@RNDX1,@FAC        fAC = X1
[0942]               *        CLR  @FAC5                 FAC = CLR
[0943]               *        DCLR @FAC6                 FAC = CLR
[0944]               *        XML  VPUSH          (A)    FAC = X1
[0945]               *        MOVE 8,G@RNDA1,@ARG        ARG = A1
[0946]               *        XML  FMUL                  FAC = X1*A1
[0947]               *        MOVE 8,G@RNDC1,@ARG        ARG = C1
[0948]               *        XML  FADD               T1=FAC = X1*A1+C1
[0949]               *        XML  VPUSH          (B)    FAC = T1
[0950]               *        MOVE 8,G@RNDEM,@ARG        ARG = 1/1E7
[0951]               *        XML  FMUL                  FAC = T1/1E7
[0952]               *        CALL GRINT              T2=FAC = INT(T1/1E7)
[0953]               *        XML  VPUSH          (C)    FAC = T2
[0954]               *        MOVE 8,G@RNDEP,@ARG        ARG = 1E7
[0955]               *        XML  FMUL                  FAC = T2*1E7
[0956]               *        DSUB 8,@VSPTR
[0957]               *        XML  SSUB           (D) X1=FAC = T1-T2*1E7
[0958]               *        MOVE 5,@FAC,V@RNDX1        FAC = X1 (new)
[0959]               *        XML  VPUSH          (E)    FAC = X1
[0960]               * COMPUTE NEW VALUE FOR X2, SAVE IT IN V@RNDX2
[0961]               *        MOVE 5,V@RNDX2,@FAC        FAC = X2
[0962]               *        CLR  @FAC5                 FAC = CLR
[0963]               *        DCLR @FAC6                 FAC = CLR
[0964]               *        MOVE 8,G@RNDA1,@ARG        ARG = A1
[0965]               *        XML  FMUL                  FAC = X2*A1
[0966]               *        DADD 8,@VSPTR
[0967]               *        XML  VPUSH          (F)    FAC = X2*A1
[0968]               *        DSUB 24,@VSPTR
[0969]               *        XML  VPOP           (G)    FAC = X1
[0970]               *        DADD 32,@VSPTR
[0971]               *        MOVE 8,G@RNDA2,@ARG        ARG = A2
[0972]               *        XML  FMUL                  FAC = X1*A2
[0973]               *        XML  SADD           (H)    FAC = X2*A1+X1*A2
[0974]               *        MOVE 8,G@RNDC2,@ARG        ARG = C2
[0975]               *        XML  FADD                  FAC = X2*A1+X1*A2
[0976]               *        XML  SADD           (J) T3=FAC = X2*A1+X1*A2
[0977]               *        DSUB 16,@VSPTR
[0978]               *        XML  VPUSH          (K)    FAC = T3
[0979]               *        MOVE 8,G@RNDEM,@ARG        ARG = 1/1E7
[0980]               *        XML  FMUL                  FAC = T3/1E7
[0981]               *        CALL GRINT              T4=FAC = INT(T3/1E7)

99/4 GPL-ASSEMBLER (Pass 3) correct                                   PAGE 0017 
EQUATES EXEC-359
[0982]               *        MOVE 8,G@RNDEP,@ARG        ARG = 1E7
[0983]               *        XML  FMUL                  FAC = T4*1E7
[0984]               *        XML  SSUB           (L) X2=FAC = T3-T4*1E7
[0985]               *        MOVE 5,@FAC,V@RNDX2        FAC = X2 (new)
[0986]               * COMPUTE NEW VALUE FOR RND, LEAVE IT IN FAC
[0987]               *        MOVE 8,G@RNDEM,@ARG        ARG = 1/1E7
[0988]               *        XML  FMUL                  FAC = X2/1E7
[0989]               *       XML  VPUSH          (M)    FAC = X2/1E7
[0990]               *        DADD 8,@VSPTR
[0991]               *        XML  VPOP           (N)    FAC = X1
[0992]               *        XML  FMUL                  FAC = X1/1E7
[0993]               *        XML  FMUL                  FAC = X1/1E14
[0994]               *        XML  SADD           (P)RND=FAC = (X2/1E7)+(X1/1E14
[0995]               *        XML  CONT
[0996]               ***********************************************************
[0997]               * CONSTANTS FOR THE RANDOM NUMBER ROUTINE
[0998]               * RNDA2  BYTE >43,>01,>2B,>59,>52,>00,>00,>00 * = 1438982
[0999]               * RNDA1  BYTE >42,>2A,>08,>15,>00,>00,>00,>00 * = 0420821
[1000]               * RNDC2  BYTE >43,>02,>0B,>20,>30,>00,>00,>00 * = 2113248
[1001]               * RNDC1  BYTE >43,>06,>36,>05,>13,>00,>00,>00 * = 6540519
[1002] A29F 43,0A,00 RNDEP  BYTE >43,>0A,>00,>00,>00,>00,>00,>00 * = 1E7
       A2A2 00,00,00
       A2A5 00,00
[1003] A2A7 3C,0A,00 RNDEM  BYTE >3C,>0A,>00,>00,>00,>00,>00,>00 * = 1/1E7
       A2AA 00,00,00
       A2AD 00,00
[1004]               ***********************************************************
[1005]               * RXB BASIC RND REPLACEMENT FROM TI BASIC
[1006] A2AF BE,4A,3F NRND   ST   >3F,@FAC       * Exponent    
[1007] A2B2 BE,10,4B        ST   >4B,@VAR5      * Loop counter
[1008] A2B5 02,63    NRND1  RAND >63            * 0?
[1009] A2B7 8E,78           CZ   @RANDOM        * No, go on
[1010] A2B9 42,C5           BR   NRND3     
[1011] A2BB 92,4A           DEC  @FAC           * 0?
[1012] A2BD 8E,4A           CZ   @FAC           * End with 0
[1013] A2BF 62,D2           BS   NRND4          * Go on
[1014] A2C1 42,B5           BR   NRND1
[1015] A2C3 02,63    NRND2  RAND >63            * Till 100
[1016] A2C5 BC,90,10 NRND3  ST   @RANDOM,*VAR5  * All digits
       A2C8 78
[1017] A2C9 D6,10,51        CEQ  >51,@VAR5      * Till >8351
[1018] A2CC 62,D4           BS   NRND5 
[1019] A2CE 90,10           INC  @VAR5          * Increase loop counter
[1020] A2D0 42,C3           BR   NRND2 
[1021] A2D2 86,4B    NRND4  CLR  @FAC1          * Set 0
[1022] A2D4 0F,75    NRND5  XML  CONT
[1023]               ***********************************************************
Link to comment
Share on other sites

 

:)

 

Yeah—and as Rich (@RXB) has noted many times before, TI Extended Basic’s RND() does its own thing and takes even longer (much longer) than TI Basic’s RND(). One of these days, perhaps, I will attempt to see how XB does it. And, even though I made a point of the possible maximum 70 times RAND can be called by TIB’s RND(), I would be willing to bet it rarely gets called more than 10 times, which would mean the first 2 calls to RAND both return 0.

 

Re “continued schooling”, I suspect that can get a little irritating, but I usually cannot help myself, particularly when someone makes the mistake :grin: of appearing to listen.

 

...lee

 

lol. Well I am old enough to know that I know very little. So I will continue listening.

 

By the way, for some reason I missed the fact that VCHAR and HCHAR could accept 32k character count until

I read the BASIC manual again. duh!

 

So I went back to the bible (TurboForth) to look at the ASM method.

 

You pointed out that in FBForth you re-wrote these things in ASM because they were so slow.

 

My HCHAR is fast because it uses VMBW.

 

My new VCHAR in Forth is about 1/3 the speed of Turbo Forth

which is not a bad number for a Forth vs pure ASM comparison.

 

I had to resort to a gratuitous variable. I will think it over more.

But this is an interesting example where stack juggling items 3 deep is a pain in the butt.

I could get to 1/2 speed of ASM probably by hand coding the LIMIT check inside the loop.

More...

( C/L is characters per line)
​( L/SCR is lines per screen )

: >VPOS ( col row -- VPOS) C/L@ * +  ;  ( calc VDP address from  col & row)

VARIABLE T
: VCHAR  ( col row char cnt -- ) ( parameter order not ideal so we shuffle)
         0 L/SCR 1- >VPOS 1-  T !  ( calc. the 1st screen limit)
         >R >R               ( -- x y ) ( push char & cnt to rstack)
         >VPOS               ( -- vdpaddr)  ( calc the Video position in memory)
         R> SWAP             ( -- char vadr) ( get the char and reverse order)
         R> 0                ( -- char vadr cnt index) ( all that crap to get this)
         ?DO                 ( -- char vadr) ( let 'er rip)
            2DUP VC!         ( write char to video memory)
            C/L+
            DUP T @ >        ( check for end of screen) 
            IF  T @ - THEN   
         LOOP
         2DROP ;


BF

Link to comment
Share on other sites

RXB has CALL HPUT(row,col,string,...) or CALL VPUT(row,col,variable$,...) and just for added measure CALL HGET(row,col,variable$,...) or CALL VGET(row,col,variable$,...)

 

These are much more powerful then HCHAR or VCHAR by a long shot. Also much more useful then GCHAR as you can fetch a string instead of just a single character.

 

But I did in RXB improve all of them by allowing more than one fetch at a time per call as in CALL GCHAR(row, col,variable,row2,col2,variable2,row3,col3,variable3,....)

Link to comment
Share on other sites

 

Yea I can save you the hassle of looking it is due to using Floating Point ALL THE TIME for all calculations unlike TI Basic RND that only return the Floating Point result.

[0898]               * Initialize random number generator 
[0899] A28D 31,00,0A INTRND MOVE 10,G@X2SEED,V@RNDX2
       A290 A3,A0,A2
       A293 95
[0900] A294 00              RTN
[0901] A295 42,03,23 X2SEED BYTE >42,>03,>23,>15,>00 * =   33521, X2 INITIAL VAL
       A298 15,00
[0902] A29A 43,02,3E X1SEED BYTE >43,>02,>3E,>2A,>17 * = 2624223, X1 INITIAL VAL
       A29D 2A,17
[0903]               ***********************************************************
[0904]               *                                                         *
[0905]               * RXB PATCH REPLACEMENT CODE FOR RND WITH TI BASIC RND    *
[0906]               *                                                         *
[0907]               ***********************************************************
[0908]               *           PSEUDO-RANDOM NUMBER GENERATOR
[0909]               *      X(N+1) = (A*X(N)+C) MOD M;  RND = X/M
[0910]               *    WHERE:                 X = X2 * 1E7 + X1
[0911]               *                           A = A2 * 1E7 + A1
[0912]               *                           C = C2 * 1E7 + C1
[0913]               *                           M = 1E14
[0914]               * ASSUMPTIONS:
[0915]               *  (1) All numbers are integers; fractional parts are
[0916]               *      truncated
[0917]               *  (2) If the variables listed below start in the ranges

99/4 GPL-ASSEMBLER (Pass 3) correct                                   PAGE 0016 
EQUATES EXEC-359
[0918]               *     specified. They will also end in the ranges specified
[0919]               *
[0920]               * CONSTANTS: 0 <= A2 < 5E6 ; 0 <= C2 < 1E7
[0921]               *            0 <= A1 < 5E6 ; 0 <= C1 < 1E7
[0922]               * VARIABLES: 0 <= X2 < 1E7 ; 0 <= T1 <= 1E14 ; 0 <= T2 < 1E
[0923]               *            0 <= X1 < 1E7 ; 0 <= T3 <= 1E14 ; 0 <= T4 < 1E
[0924]               *
[0925]               *        STACK USAGE:
[0926]               *            CONSTANT REFS      CONTANT REFS    CONTANT REF
[0927]               * +---------+      IN/OUT            IN/OUT          IN/OUT
[0928]               * | STACK+4 | X2*A1(F)(H)       --    ----      --    ----
[0929]               * +---------+
[0930]               * | STACK+3 |   T2 (C)(J)       --    ----      --    ----
[0931]               * +---------+
[0932]               * | STACK+2 |   T1 (B)(D)   new X1   (E)(N)     --    ----
[0933]               * +---------+
[0934]               * | STACK+1 |old X1(A)(G)       T3   (K)(L) new X2   (M)(P)
[0935]               * +---------+
[0936]               ***********************************************************
[0937]               * COMPUTE NEW VALUE FOR X1, SAVE IT IN V@RNDX1
[0938]               *                             STACK
[0939]               *                               SREFS   FAC CONTENTS
[0940]               * NRND   MOVE 5,V@RNDX1,@FAC        FAC = X1
[0941]               *        MOVE 5,V@RNDX1,@FAC        fAC = X1
[0942]               *        CLR  @FAC5                 FAC = CLR
[0943]               *        DCLR @FAC6                 FAC = CLR
[0944]               *        XML  VPUSH          (A)    FAC = X1
[0945]               *        MOVE 8,G@RNDA1,@ARG        ARG = A1
[0946]               *        XML  FMUL                  FAC = X1*A1
[0947]               *        MOVE 8,G@RNDC1,@ARG        ARG = C1
[0948]               *        XML  FADD               T1=FAC = X1*A1+C1
[0949]               *        XML  VPUSH          (B)    FAC = T1
[0950]               *        MOVE 8,G@RNDEM,@ARG        ARG = 1/1E7
[0951]               *        XML  FMUL                  FAC = T1/1E7
[0952]               *        CALL GRINT              T2=FAC = INT(T1/1E7)
[0953]               *        XML  VPUSH          (C)    FAC = T2
[0954]               *        MOVE 8,G@RNDEP,@ARG        ARG = 1E7
[0955]               *        XML  FMUL                  FAC = T2*1E7
[0956]               *        DSUB 8,@VSPTR
[0957]               *        XML  SSUB           (D) X1=FAC = T1-T2*1E7
[0958]               *        MOVE 5,@FAC,V@RNDX1        FAC = X1 (new)
[0959]               *        XML  VPUSH          (E)    FAC = X1
[0960]               * COMPUTE NEW VALUE FOR X2, SAVE IT IN V@RNDX2
[0961]               *        MOVE 5,V@RNDX2,@FAC        FAC = X2
[0962]               *        CLR  @FAC5                 FAC = CLR
[0963]               *        DCLR @FAC6                 FAC = CLR
[0964]               *        MOVE 8,G@RNDA1,@ARG        ARG = A1
[0965]               *        XML  FMUL                  FAC = X2*A1
[0966]               *        DADD 8,@VSPTR
[0967]               *        XML  VPUSH          (F)    FAC = X2*A1
[0968]               *        DSUB 24,@VSPTR
[0969]               *        XML  VPOP           (G)    FAC = X1
[0970]               *        DADD 32,@VSPTR
[0971]               *        MOVE 8,G@RNDA2,@ARG        ARG = A2
[0972]               *        XML  FMUL                  FAC = X1*A2
[0973]               *        XML  SADD           (H)    FAC = X2*A1+X1*A2
[0974]               *        MOVE 8,G@RNDC2,@ARG        ARG = C2
[0975]               *        XML  FADD                  FAC = X2*A1+X1*A2
[0976]               *        XML  SADD           (J) T3=FAC = X2*A1+X1*A2
[0977]               *        DSUB 16,@VSPTR
[0978]               *        XML  VPUSH          (K)    FAC = T3
[0979]               *        MOVE 8,G@RNDEM,@ARG        ARG = 1/1E7
[0980]               *        XML  FMUL                  FAC = T3/1E7
[0981]               *        CALL GRINT              T4=FAC = INT(T3/1E7)

99/4 GPL-ASSEMBLER (Pass 3) correct                                   PAGE 0017 
EQUATES EXEC-359
[0982]               *        MOVE 8,G@RNDEP,@ARG        ARG = 1E7
[0983]               *        XML  FMUL                  FAC = T4*1E7
[0984]               *        XML  SSUB           (L) X2=FAC = T3-T4*1E7
[0985]               *        MOVE 5,@FAC,V@RNDX2        FAC = X2 (new)
[0986]               * COMPUTE NEW VALUE FOR RND, LEAVE IT IN FAC
[0987]               *        MOVE 8,G@RNDEM,@ARG        ARG = 1/1E7
[0988]               *        XML  FMUL                  FAC = X2/1E7
[0989]               *       XML  VPUSH          (M)    FAC = X2/1E7
[0990]               *        DADD 8,@VSPTR
[0991]               *        XML  VPOP           (N)    FAC = X1
[0992]               *        XML  FMUL                  FAC = X1/1E7
[0993]               *        XML  FMUL                  FAC = X1/1E14
[0994]               *        XML  SADD           (P)RND=FAC = (X2/1E7)+(X1/1E14
[0995]               *        XML  CONT
[0996]               ***********************************************************
[0997]               * CONSTANTS FOR THE RANDOM NUMBER ROUTINE
[0998]               * RNDA2  BYTE >43,>01,>2B,>59,>52,>00,>00,>00 * = 1438982
[0999]               * RNDA1  BYTE >42,>2A,>08,>15,>00,>00,>00,>00 * = 0420821
[1000]               * RNDC2  BYTE >43,>02,>0B,>20,>30,>00,>00,>00 * = 2113248
[1001]               * RNDC1  BYTE >43,>06,>36,>05,>13,>00,>00,>00 * = 6540519
[1002] A29F 43,0A,00 RNDEP  BYTE >43,>0A,>00,>00,>00,>00,>00,>00 * = 1E7
       A2A2 00,00,00
       A2A5 00,00
[1003] A2A7 3C,0A,00 RNDEM  BYTE >3C,>0A,>00,>00,>00,>00,>00,>00 * = 1/1E7
       A2AA 00,00,00
       A2AD 00,00
[1004]               ***********************************************************
[1005]               * RXB BASIC RND REPLACEMENT FROM TI BASIC
[1006] A2AF BE,4A,3F NRND   ST   >3F,@FAC       * Exponent    
[1007] A2B2 BE,10,4B        ST   >4B,@VAR5      * Loop counter
[1008] A2B5 02,63    NRND1  RAND >63            * 0?
[1009] A2B7 8E,78           CZ   @RANDOM        * No, go on
[1010] A2B9 42,C5           BR   NRND3     
[1011] A2BB 92,4A           DEC  @FAC           * 0?
[1012] A2BD 8E,4A           CZ   @FAC           * End with 0
[1013] A2BF 62,D2           BS   NRND4          * Go on
[1014] A2C1 42,B5           BR   NRND1
[1015] A2C3 02,63    NRND2  RAND >63            * Till 100
[1016] A2C5 BC,90,10 NRND3  ST   @RANDOM,*VAR5  * All digits
       A2C8 78
[1017] A2C9 D6,10,51        CEQ  >51,@VAR5      * Till >8351
[1018] A2CC 62,D4           BS   NRND5 
[1019] A2CE 90,10           INC  @VAR5          * Increase loop counter
[1020] A2D0 42,C3           BR   NRND2 
[1021] A2D2 86,4B    NRND4  CLR  @FAC1          * Set 0
[1022] A2D4 0F,75    NRND5  XML  CONT
[1023]               ***********************************************************

 

This is great stuff. Thanks!

 

BF

  • Like 1
Link to comment
Share on other sites

  • 3 months later...

Further to this discussion about random numbers.

I tried to GROK the RXB GPL code and translate it to integer Forth in some fashion and I don't quite understand it Rich.

So I want to take the equation in the comments and just code it in integers.

 

So given your comments from the code, can you confirm some things for me:

  1. X(n+1) means the next random number in the sequence
  2. X(n) would then be the last random number created by the function
  3. X, A and C must be calculated first by a function using the values [ X1,X2,A1,A2,C1,C2]
  4. M is a constant
  5. Any random number in the sequence must also be divided by M per RND=X/M
    ( I think that may only work for a floating point based random number generator)
 *           PSEUDO-RANDOM NUMBER GENERATOR
 *      X(N+1) = (A*X(N)+C) MOD M;  RND = X/M
 *    WHERE:                 X = X2 * 1E7 + X1
 *                           A = A2 * 1E7 + A1
 *                           C = C2 * 1E7 + C1
 *                           M = 1E14

Link to comment
Share on other sites

While looking into random numbers I thought I would compare how TI-BASIC and XB look so I wrote this little program.

You can clearly see that TI-BASIC has a better random number generator at least for 300 numbers.

 

I will use this to help create a random number generator in CAMEL Forth.

 

post-50750-0-29082900-1500575751.jpgpost-50750-0-82970800-1500575757.jpg

100 REM  TEST TI99 RANDOM GENERATOR
110 DIM HIST(32)
120 REM  Format screen
140 CALL CLEAR
150 N=300
160 REM  increment HIST() at random indices 
170 PRINT "Gen.";N;"random numbers..."
180 FOR CNT=1 TO N
190 R=INT(RND*33)
200 HIST(R)=HIST(R)+1
210 NEXT CNT
220 REM  show histogram
230 CALL CLEAR
240 PRINT "TI-BASIC Histogram:";N;"no.s"
250 FOR COL=1 TO 32
260 CALL VCHAR(22-HIST(COL),COL,30,HIST(COL))
270 NEXT COL
280 GOTO 280

Edited by TheBF
Link to comment
Share on other sites

That's cool to see Rich. Thanks

 

Can you explain how you made RXB's version faster than TI-BASIC?

 

It kind of indicates that regular XB could use a "CALL RNDM()" sub-program to improve game performance.

  • Like 1
Link to comment
Share on other sites

That's cool to see Rich. Thanks

 

Can you explain how you made RXB's version faster than TI-BASIC?

 

It kind of indicates that regular XB could use a "CALL RNDM()" sub-program to improve game performance.

RXB is faster than TI BASIC because CALLs are painfully slow in TI BASIC. It is faster than TI XB because it uses the TI BASIC random number generator. You can see in post #3 that TI BASIC is a bit faster than RXB in the only true random number test which is video #1 (RXB NEW RND). Video #3 (RXB RND TEST 3) is not a random number test at all; it does show that RXB is faster than TI BASIC, but we already knew that.

 

For what it's worth, I am exploring some ideas that have the potential to make TI BASIC noticeably faster than XB or RXB by 1.5x or even more. This involves finding methods to speed up CALL LINK.

Link to comment
Share on other sites

RXB is faster than TI BASIC because CALLs are painfully slow in TI BASIC. It is faster than TI XB because it uses the TI BASIC random number generator. You can see in post #3 that TI BASIC is a bit faster than RXB in the only true random number test which is video #1 (RXB NEW RND). Video #3 (RXB RND TEST 3) is not a random number test at all; it does show that RXB is faster than TI BASIC, but we already knew that.

 

For what it's worth, I am exploring some ideas that have the potential to make TI BASIC noticeably faster than XB or RXB by 1.5x or even more. This involves finding methods to speed up CALL LINK.

Actually most of the reason for XB being faster is the 12K ROM included with XB that TI Basic does not have.

 

So basically (Pun not intended) you are going to add ROM to TI Basic to make it like XB or RXB.

Link to comment
Share on other sites

You should know that TI Basic's (TIB's) Pseudo-Random Number Generator (PRNG) always starts with the same number in >83C0, i.e., >3567. This means you will get the same distribution every time you run the program. You should put a RANDOMIZE statement before the loop to make the outcome less predictable. Also, RND and RANDOMIZE only use the LSB of >83C0 as the random number seed.

 

TI Extended Basic's PRNG, on the other hand, changes >83C0 with every interrupt until a program is running. It is very unlikely it will start with the same number in >83C0 with two program starts. Also, TI Extended Basic uses the entire word at >83C0.

 

I was wrong about TI Extended Basic's (XB's) initial PRNG seed. :-o Updates to >83C0 are unrelated to the PRNG in XB. XB actually also starts out with the same seed every time it starts, but it is a much larger number than TIB's initial seed of >3567: 335,212,624,223. This initial value is stored in the XB GROM as the first 5 bytes of each of two floating point (FP) numbers. FP numbers are stored in 8 bytes, so the seed for calculating a new PRN is composed by first filling in the remaining 3 bytes of each FP number with zeroes, multiplying the first (33,521) by 107 and adding the second (2,624,223). The two parts of the seed are updated separately each time RND is called.

 

TurboForth, TI Forth and fbForth all use the entire word at >83C0. They also have both integer and floating point PRNGs.

 

...lee

 

[Edits are in this color.]

Link to comment
Share on other sites

300 random numbers is nowhere near enough. If you generate 3000 I bet the histogram would be way more even. And 3 million would be even more so. Also, keep in mind that if your random number generator produced 1,2,3,4,5...32 repeatedly you would get an even histogram, but the numbers would be anything but random..

Link to comment
Share on other sites

The problem with this test is that you can get a perfect distribution by changing line 190 to:

 

190 R=INT(CNT*32/(N-8 ))

 

So a function that gives a perfect distribution might not be random at all. ;)

 

I don't exactly understand what you mean.

 

I am not the "sharpest knife in the drawer" as we say, but if you wanted R to relate to a random number,

why would you use a function that does not have a random number in it somewhere? :?

 

(or did I miss a joke here)

  • Like 1
Link to comment
Share on other sites

You should know that TI Basic's Pseudo-Random Number Generator (PRNG) always starts with the same number in >83C0, i.e., >3567. This means you will get the same distribution every time you run the program. You should put a RANDOMIZE statement before the loop to make the outcome less predictable. Also, RND and RANDOMIZE only use the LSB of >83C0 as the random number seed.

 

TI Extended Basic's PRNG, on the other hand, changes >83C0 with every interrupt until a program is running. It is very unlikely it will start with the same number in >83C0 with two program starts. Also, TI Extended Basic uses the entire word at >83C0.

 

TurboForth, TI Forth and fbForth also use the entire word at >83C0. They also have both integer and floating point PRNGs.

 

...lee

 

I was actually trying to get that consistent result for both systems, by not using RANDOMIZE.

My assumptions are probably suspect based on your information here.

 

I was playing with the Lehmer PRNG from Wikipedia.

It mentions that the Sinclair ZX81 used >FFFF+1 as a prime number but that would mean I would need a 32bit MOD routine which I didn't want to create.

I used 65521 instead and got some preliminary results that seemed ok.

 

I will take a look at the rest of the Forth family source code and see how the big boys do it.

 

As always thanks for the insights.

 

B

Link to comment
Share on other sites

(or did I miss a joke here)

 

Yes.

 

Rasmus just said that you cannot judge the quality of the random generator by looking at the distribution alone, because you could create a "perfect" distribution by some function that does not even produce random numbers.

 

It's the typical "implies" semantics in mathematics. Perfect random generator => perfect distribution, but the reverse does not hold.

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...