Forums before death by AOL, social media and spammers... "We can't have nice things"
|    comp.lang.forth    |    Forth programmers eat a lot of Bratwurst    |    117,927 messages    |
[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]
|    Message 117,599 of 117,927    |
|    Hans Bezemer to Anton Ertl    |
|    Re: Generating a random sequence of Fort    |
|    01 Oct 25 17:11:21    |
   
   From: the.beez.speaks@gmail.com   
      
   I used something similar - but with a whole slew of stack operations.   
   Very handy thingy. I use it until this day.   
      
   ( abc -- abcabc) >r over over r@ rot rot r> \ >r 2dup r@ -rot r>   
      
   Hans Bezemer   
      
   On 30-09-2025 18:33, Anton Ertl wrote:   
   > I wanted to generate a random sequence consisting of a number, NOOP,   
   > and DROP. When EVALUATEing the sequence, starting with an empty   
   > stack, it should end with an empty stack, and should not underflow the   
   > stack.   
   >   
   > I implemented this twice. The first attempt just generated a random   
   > word/number in the normal case, and a specific kind of word/number in   
   > the boundary cases:   
   >   
   > : genseq {: u -- :}   
   > 0 u 0 do   
   > case   
   > dup 0= ?of 1+ ." 9 " endof   
   > dup i + u u>= ?of 1- ." drop " endof   
   > dup i + 1+ u u>= ?of ." noop " endof   
   > rnd 3 um* nip 1- dup case   
   > -1 of ." drop " endof   
   > 0 of ." noop " endof   
   > 1 of ." 8 " endof   
   > endcase   
   > +   
   > 0 endcase   
   > loop   
   > drop ;   
   >   
   > When I do 16 GENSEQ with seed 1234, I get the following sequence:   
   >   
   > 9 drop 9 8 8 noop drop drop 8 noop drop noop noop 8 drop drop   
   >   
   > The requirements are distributed across several places in this word,   
   > which I did not like. I also did not like the non-randomness of the   
   > sequence of DROPs at the end, and the non-randomness of the 9 whenever   
   > the stack is empty. I also found that I needed to add a clause for   
   > when the stack depth is one less than the number of remaining words.   
   >   
   > So I thought about other ways to do it.   
   >   
   > Eventually I came up with the following approach: Starts with counters   
   > for the different kinds of words/numbers. Whenever one word/number is   
   > generated, its counter is reduced. At each step the probability of   
   > generating a kind of word/number is proportional to the remaining   
   > counter for that word/number. The same-depth requirement is   
   > implemented by having the same initial counter for the number and   
   > DROP. The no-underflow requirement is implemented by skipping the   
   > output of a DROP if the count of remaining DROPs = the count of the   
   > remaining numbers.   
   >   
   > Here's the code:   
   >   
   > create counts 3 cells allot   
   >   
   > : initcounts ( u -- )   
   > dup 3 / dup counts ! dup counts 2 th ! 2* - counts cell+ ! ;   
   >   
   > : .counts ( -- )   
   > counts 3 cell array>mem mem+do   
   > i @ 4 .r   
   > loop ;   
   >   
   > : countsth-- ( u -- )   
   > -1 counts rot th +! ;   
   >   
   > : select1 ( u -- )   
   > \ u is the index of the word   
   > dup case   
   > 0 of ." 9 " countsth-- endof   
   > 1 of ." noop " countsth-- endof   
   > 2 of counts @ counts 2 th @ u< if   
   > ." drop " countsth--   
   > else   
   > drop endif   
   > endof   
   > endcase ;   
   >   
   > : sum ( addr u -- u2 )   
   > \ addr u is an array with u elements, u2 is the sum of the elements   
   > 0 -rot cell array>mem mem+do   
   > i @ +   
   > loop ;   
   >   
   > : genseq ( u -- )   
   > initcounts   
   > begin   
   > counts 3 sum dup while   
   > rnd um* nip ( sum )   
   > 3 0 u+do ( sum1 )   
   > counts i th @ 2dup u< if   
   > i select1 then   
   > - loop   
   > drop   
   > repeat   
   > drop ;   
   >   
   > The code is much longer, but I like it better. The requirements are   
   > concentrated in two places.   
   >   
   > 16 GENSEQ generates   
   >   
   > 9 9 noop noop drop noop 9 drop noop drop noop 9 drop 9 noop drop   
   >   
   > for seed 123. A disadvantage of this approach is that it does not   
   > generate a word/number on each iteration through the main loop. I   
   > have thought about how to achieve this, but the result would be quite   
   > a bit more complex; it's also only a minor issue. E.g., for   
   > generating 1000 words/numbers with seed 123, the main loop has 1036   
   > iterations.   
   >   
   > The second approach takes quite a bit more time; for generating a   
   > million words/numbers into a string on a Zen 4, 192_876_892 cycles   
   > compared to 146_644_156 cycles.   
   >   
   > The original goal was to produce a sequence where various parts of the   
   > text interpreter have branch mispredictions; the less predictable the   
   > sequence, the better. In this respect the second sequence is   
   > significantly better. For a sequence of 1000 words/numbers,   
   > text-interpreted 1000 times, the number of mispredictions is:   
   >   
   > 728_322 first approach   
   > 821_813 second approach   
   >   
   > (with 247_125 mispredictions coming from (mainly) Gforth startup).   
   >   
   > - anton   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   
|
[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]
(c) 1994, bbs@darkrealms.ca